using System.Text.Json; using Microsoft.AspNetCore.Mvc; using Nop.Core.Domain.Common; using Nop.Core.Domain.Customers; using Nop.Plugin.Misc.FruitBankPlugin.Models; using Nop.Plugin.Misc.FruitBankPlugin.Services; using Nop.Services.Customers; using Nop.Web.Areas.Admin.Models.Customers; using Nop.Web.Framework.Components; namespace Nop.Plugin.Misc.FruitBankPlugin.Components; [ViewComponent(Name = "CustomerCreditWidget")] public class CustomerCreditWidgetViewComponent : NopViewComponent { private readonly ICustomerCreditService _customerCreditService; private readonly FruitBankAttributeService _attributeService; private readonly ICustomerService _customerService; public CustomerCreditWidgetViewComponent( ICustomerCreditService customerCreditService, FruitBankAttributeService attributeService, ICustomerService customerService) { _customerCreditService = customerCreditService; _attributeService = attributeService; _customerService = customerService; } public async Task InvokeAsync(string widgetZone, object additionalData) { if (additionalData is not CustomerModel customerModel) return Content(""); var customerId = customerModel.Id; var credit = await _customerCreditService.GetByCustomerIdAsync(customerId); var outstanding = await _customerCreditService.GetOutstandingBalanceAsync(customerId); // Hiányzó attribútum (null) = köteles — a kapu is így dönt (CreateMissingEkaerHistories: csak az explicit // false mentesít); a checkbox pipáltat mutat, amíg explicit ki nem veszik. var isEkaer = await _attributeService .GetGenericAttributeValueAsync(customerId, FruitBankPluginConst.IsEkaerAttribute, storeId: 0) ?? true; var model = new CustomerCreditWidgetModel { CustomerId = customerId, HasCreditLimit = credit != null, CreditLimit = credit?.CreditLimit ?? 0m, OutstandingBalance = outstanding, RemainingCredit = credit != null ? credit.CreditLimit - outstanding : (decimal?)null, Comment = credit?.Comment, IsEkaer = isEkaer }; await PopulateSitesAsync(model, customerId); await PopulatePlatesAsync(model, customerId); return View("~/Plugins/Misc.FruitBankPlugin/Views/CustomerCreditWidget.cshtml", model); } private async Task PopulatePlatesAsync(CustomerCreditWidgetModel model, int customerId) { var json = await _attributeService .GetGenericAttributeValueAsync(customerId, FruitBankPluginConst.CustomerLicensePlatesAttribute, storeId: 0); var entries = ParsePlates(json); model.LicensePlates = entries .Select(e => new CustomerLicensePlateRow { Plate = e.Plate, IsDefault = e.IsDefault }) .ToList(); model.PlateCount = model.LicensePlates.Count; model.DefaultPlate = model.LicensePlates.FirstOrDefault(p => p.IsDefault)?.Plate; } private static List ParsePlates(string? json) { if (string.IsNullOrWhiteSpace(json)) return new(); try { return JsonSerializer.Deserialize>(json) ?? new(); } catch { return new(); } } // Merge the customer's current addresses with the saved site list (orphaned // address ids — deleted addresses — are dropped because we iterate addresses). private async Task PopulateSitesAsync(CustomerCreditWidgetModel model, int customerId) { var addresses = await _customerService.GetAddressesByCustomerIdAsync(customerId); var savedJson = await _attributeService .GetGenericAttributeValueAsync(customerId, FruitBankPluginConst.CustomerSitesAttribute, storeId: 0); var saved = ParseSites(savedJson); var savedById = saved.ToDictionary(s => s.AddressId); foreach (var addr in addresses) { savedById.TryGetValue(addr.Id, out var entry); model.SiteAddresses.Add(new CustomerSiteAddressRow { AddressId = addr.Id, Display = FormatAddress(addr), IsSite = entry != null, IsDefault = entry?.IsDefault ?? false }); } var sites = model.SiteAddresses.Where(a => a.IsSite).ToList(); model.SiteCount = sites.Count; model.DefaultSiteDisplay = sites.FirstOrDefault(a => a.IsDefault)?.Display; } private static List ParseSites(string? json) { if (string.IsNullOrWhiteSpace(json)) return new(); try { return JsonSerializer.Deserialize>(json) ?? new(); } catch { return new(); } } private static string FormatAddress(Address a) { var name = !string.IsNullOrWhiteSpace(a.Company) ? a.Company : $"{a.FirstName} {a.LastName}".Trim(); var locality = $"{a.ZipPostalCode} {a.City}".Trim(); var parts = new[] { name, a.Address1, locality } .Where(p => !string.IsNullOrWhiteSpace(p)); var display = string.Join(", ", parts); return string.IsNullOrWhiteSpace(display) ? $"#{a.Id}" : display; } }