using FruitBank.Common.Enums; using FruitBank.Common.Interfaces; using FruitBank.Common.Server; using Mango.Nop.Core.Dtos; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; using Nop.Core; using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Common; using Nop.Core.Domain.Customers; using Nop.Core.Domain.Messages; using Nop.Core.Domain.Orders; using Nop.Core.Domain.Tax; using Nop.Core.Events; using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; using Nop.Plugin.Misc.FruitBankPlugin.Models; using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders; using Nop.Services.Attributes; using Nop.Services.Catalog; using Nop.Services.Common; using Nop.Services.Customers; using Nop.Services.Events; using Nop.Services.Localization; using Nop.Services.Messages; using Nop.Services.Orders; using Nop.Services.Plugins; using Nop.Web.Framework.Events; using Nop.Web.Framework.Menu; using Nop.Web.Models.Sitemap; using NUglify.JavaScript.Syntax; using System.Linq; using System.Xml.Linq; namespace Nop.Plugin.Misc.FruitBankPlugin.Services { public class EventConsumer : BaseAdminMenuCreatedEventConsumer, IConsumer>, IConsumer>, IConsumer, IConsumer>, IConsumer { private readonly IGenericAttributeService _genericAttributeService; private readonly IProductService _productService; private readonly ISpecificationAttributeService _specificationAttributeService; private readonly IOrderService _orderService; private readonly IProductAttributeService _productAttributeService; private readonly IWorkContext _workContext; private readonly IStoreContext _storeContext; private readonly IAdminMenu _adminMenu; private readonly ILocalizationService _localizationService; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IAddressService _addressService; private readonly FruitBankAttributeService _fruitBankAttributeService; private readonly FruitBankDbContext _dbContext; private readonly IAttributeParser _attributeParser; private readonly ICustomerService _customerService; private readonly IWorkflowMessageService _workflowMessageService; private readonly FruitBankNotificationService _fruitBankNotificationService; public EventConsumer( IGenericAttributeService genericAttributeService, IProductService productService, ISpecificationAttributeService specificationAttributeService, IOrderService orderService, IProductAttributeService productAttributeService, IPluginManager pluginManager, IWorkContext workContext, IStoreContext storeContext, IAdminMenu adminMenu, ILocalizationService localizationService, IHttpContextAccessor httpContextAccessor, IAddressService addressService, FruitBankAttributeService fruitBankAttributeService, FruitBankDbContext dbContext, IAttributeParser attributeParser, ICustomerService customerService, IWorkflowMessageService workflowMessageService, FruitBankNotificationService fruitBankNotificationService ) : base(pluginManager) { _genericAttributeService = genericAttributeService; _productService = productService; _specificationAttributeService = specificationAttributeService; _orderService = orderService; _productAttributeService = productAttributeService; _workContext = workContext; _storeContext = storeContext; _adminMenu = adminMenu; _localizationService = localizationService; _httpContextAccessor = httpContextAccessor; _addressService = addressService; _fruitBankAttributeService = fruitBankAttributeService; _dbContext = dbContext; _attributeParser = attributeParser; _customerService = customerService; _workflowMessageService = workflowMessageService; _fruitBankNotificationService = fruitBankNotificationService; } protected override string PluginSystemName => "Misc.FruitBankPlugin"; public async Task HandleEventAsync(OrderPlacedEvent eventMessage) { var order = eventMessage?.Order; if (order == null) return; // Transfer the customer's chosen delivery datetime to the order as DateOfReceipt var customer = await _customerService.GetCustomerByIdAsync(order.CustomerId); if (customer == null) return; var storeId = order.StoreId; const string pendingKey = "QuickOrderPendingDeliveryDateTime"; var pendingDateTime = await _fruitBankAttributeService .GetGenericAttributeValueAsync(order.CustomerId, pendingKey, storeId); if (pendingDateTime.HasValue) { await _fruitBankAttributeService .InsertOrUpdateGenericAttributeAsync( order.Id, nameof(IOrderDto.DateOfReceipt), pendingDateTime.Value, storeId); // Clean up — the value has been transferred to the order await _fruitBankAttributeService .DeleteGenericAttributeAsync(order.CustomerId, pendingKey, storeId); Console.WriteLine($"[EventConsumer] OrderPlaced #{order.Id} – DateOfReceipt set to {pendingDateTime.Value:u}"); } } public async Task HandleEventAsync(EntityUpdatedEvent eventMessage) { await SaveOrderCustomAttributesAsync(eventMessage.Entity); if (eventMessage.Entity == null) return; var orderDto = await _dbContext.OrderDtos.GetByIdAsync(eventMessage.Entity.Id, true); if (orderDto == null) return; if (orderDto.MeasuringStatus == MeasuringStatus.Audited) { var alreadySent = await _fruitBankAttributeService .GetGenericAttributeValueAsync(eventMessage.Entity.Id, "OrderAuditedNotificationSent"); if (!alreadySent) { await _fruitBankNotificationService .SendOrderAuditedCustomerNotificationAsync(eventMessage.Entity, orderDto.IsMeasurable); await _fruitBankAttributeService .InsertOrUpdateGenericAttributeAsync( eventMessage.Entity.Id, "OrderAuditedNotificationSent", true); } } else if (orderDto.MeasuringStatus == MeasuringStatus.Started) { var alreadySent = await _fruitBankAttributeService .GetGenericAttributeValueAsync(eventMessage.Entity.Id, "OrderStartedNotificationSent"); if (!alreadySent) { await _fruitBankNotificationService .SendOrderStartedCustomerNotificationAsync(eventMessage.Entity, orderDto.IsMeasurable); await _fruitBankAttributeService .InsertOrUpdateGenericAttributeAsync( eventMessage.Entity.Id, "OrderStartedNotificationSent", true); } } } private async Task SaveOrderCustomAttributesAsync(Order order) { if (order == null) return; var hasForm = _httpContextAccessor.HttpContext?.Request?.HasFormContentType ?? false; var form = hasForm ? _httpContextAccessor.HttpContext.Request.Form : null; if (form == null || form.Count == 0) return; //if (form.ContainsKey(nameof(IMeasurable.IsMeasurable))) //{ // var isMeasurable = form[nameof(IMeasurable.IsMeasurable)].ToString().Contains("true"); // //var isMeasurable = CommonHelper.To(form[nameof(IMeasurable.IsMeasurable)].ToString()); // await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync(order.Id, nameof(IMeasurable.IsMeasurable), isMeasurable); //} if (form.ContainsKey(nameof(IOrderDto.DateOfReceipt))) { var dateOfReceiptString = form[nameof(IOrderDto.DateOfReceipt)]; if (string.IsNullOrWhiteSpace(dateOfReceiptString)) return; if (DateTime.TryParse(dateOfReceiptString, out var dateOfReceipt)) await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync(order.Id, nameof(IOrderDto.DateOfReceipt), dateOfReceipt); } } public override async Task HandleEventAsync(AdminMenuCreatedEvent eventMessage) { var rootNode = eventMessage.RootMenuItem; var shippingsListMenuItem = new AdminMenuItem { Visible = true, OpenUrlInNewTab = true, SystemName = "FruitBank", Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.ShippingsList"), // You can localize this with await _localizationService.GetResourceAsync("...") IconClass = "fas fa-shipping-fast", //Url = _adminMenu.GetMenuItemUrl("Shipping", "List") Url = "https://app.fruitbank.hu" }; //var createShippingMenuItem = new AdminMenuItem //{ // Visible = true, // SystemName = "Shippings.Create", // Title = "Create Shipping", // IconClass = "far fa-circle", // Url = _adminMenu.GetMenuItemUrl("Shipping", "Create") //}; //var editShippingMenuItem = new AdminMenuItem //{ // Visible = true, // SystemName = "Shippings.Edit", // Title = "Edit Shipping", // IconClass = "far fa-circle", // Url = _adminMenu.GetMenuItemUrl("Shipping", "Edit") //}; // Create a new top-level menu item var shippingsMenuItem = new AdminMenuItem { Visible = true, SystemName = "FruitBank", Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.Shippings"), // You can localize this with await _localizationService.GetResourceAsync("...") IconClass = "fas fa-shipping-fast", //Url = _adminMenu.GetMenuItemUrl("Shipping", "List") //ChildNodes = [shippingsListMenuItem, createShippingMenuItem, editShippingMenuItem] ChildNodes = [shippingsListMenuItem] }; var shippingConfigurationItem = rootNode; shippingConfigurationItem.ChildNodes.Insert(2, shippingsMenuItem); // Create a new top-level menu item var voiceOrderMenuItem = new AdminMenuItem { Visible = true, SystemName = "FruitBank", Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.VoiceOrder"), IconClass = "fas fa-microphone", Url = _adminMenu.GetMenuItemUrl("VoiceOrder", "Create") }; shippingConfigurationItem.ChildNodes.Insert(3, voiceOrderMenuItem); var preorderAvailabilityMenuItem = new AdminMenuItem { Visible = true, SystemName = "PreorderAvailability", Title = "Előrendelés — elérhetőség", IconClass = "fas fa-calendar-check", Url = _adminMenu.GetMenuItemUrl("PreorderAvailability", "Index") }; //shippingConfigurationItem.ChildNodes.Insert(4, preorderAvailabilityMenuItem); var preorderListMenuItem = new AdminMenuItem { Visible = true, SystemName = "Preorders.List", Title = "Előrendelések", IconClass = "fas fa-calendar-plus", Url = _adminMenu.GetMenuItemUrl("PreorderAdmin", "List") }; var preordersRootMenuItem = new AdminMenuItem { Visible = true, SystemName = "FruitBank", Title = "Előrendelés", //Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.Preorders"), // You can localize this with await _localizationService.GetResourceAsync("...") IconClass = "fas fa-heart", //Url = _adminMenu.GetMenuItemUrl("Shipping", "List") //ChildNodes = [shippingsListMenuItem, createShippingMenuItem, editShippingMenuItem] ChildNodes = [preorderAvailabilityMenuItem, preorderListMenuItem] }; rootNode.ChildNodes.Insert(3, preordersRootMenuItem); //shippingConfigurationItem.ChildNodes.Insert(5, preorderListMenuItem); // Create a new top-level menu item var InvoiceSyncMenuItem = new AdminMenuItem { Visible = true, SystemName = "FruitBank", Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.InnVoiceOrderSync"), // You can localize this with await _localizationService.GetResourceAsync("...") IconClass = "fas fa-file-invoice", Url = _adminMenu.GetMenuItemUrl("InnVoiceOrderSync", "Index") //ChildNodes = [shippingsListMenuItem, createShippingMenuItem, editShippingMenuItem] }; shippingConfigurationItem.ChildNodes.Insert(4, InvoiceSyncMenuItem); // Create a new top-level menu item var AppDownloadMenuItem = new AdminMenuItem { Visible = true, SystemName = "FruitBank", Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.AppDownload"), // You can localize this with await _localizationService.GetResourceAsync("...") IconClass = "fas fa-mobile", Url = _adminMenu.GetMenuItemUrl("AppDownload", "Index") //ChildNodes = [shippingsListMenuItem, createShippingMenuItem, editShippingMenuItem] }; shippingConfigurationItem.ChildNodes.Insert(4, AppDownloadMenuItem); var invoiceListMenuItem = new AdminMenuItem { Visible = true, SystemName = "FruitBank", Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.InvoicesList"), // You can localize this with await _localizationService.GetResourceAsync("...") IconClass = "fas fa-file-invoice", Url = _adminMenu.GetMenuItemUrl("Invoices", "List") }; // Create a new top-level menu item var invoicesMenuItem = new AdminMenuItem { Visible = true, SystemName = "FruitBank", Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.Invoices"), // You can localize this with await _localizationService.GetResourceAsync("...") IconClass = "fas fa-file-invoice", //Url = _adminMenu.GetMenuItemUrl("Shipping", "List") ChildNodes = [invoiceListMenuItem] }; var invoiceConfigurationItem = rootNode; invoiceConfigurationItem.ChildNodes.Insert(2, invoicesMenuItem); var configurationItem = rootNode.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Configuration")); if (configurationItem is null) return; var shippingItem = configurationItem.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Shipping")); var widgetsItem = configurationItem.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Widgets")); if (shippingItem is null && widgetsItem is null) return; var index = shippingItem is not null ? configurationItem.ChildNodes.IndexOf(shippingItem) : -1; if (index < 0) index = widgetsItem is not null ? configurationItem.ChildNodes.IndexOf(widgetsItem) : -1; if (index < 0) return; configurationItem.ChildNodes.Insert(index + 1, new AdminMenuItem { Visible = true, SystemName = "FruitBank", Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.AI"), IconClass = "far fa-dot-circle", ChildNodes = new List { new() { Visible = true, SystemName = "FruitBank", Title = await _localizationService.GetResourceAsync("Plugins.Misc.FruitBankPlugin.Menu.Configure"), IconClass = "far fa-circle", Url = _adminMenu.GetMenuItemUrl("FruitBankPlugin", "Configure"), } } }); } public async Task HandleEventAsync(EntityInsertedEvent eventMessage) { await ProcessCustomerEventAsync(eventMessage?.Entity); } public async Task HandleEventAsync(EntityUpdatedEvent eventMessage) { await ProcessCustomerEventAsync(eventMessage?.Entity); } private async Task ProcessCustomerEventAsync(Customer customer) { if (customer == null) { return; } if (!IsRegisteredCustomer(customer)) { return; } await EnsureBillingAddressAsync(customer); await SynchronizeTaxInformationAsync(customer); } private bool IsRegisteredCustomer(Customer customer) { var customerRoles = _dbContext.GetCustomerRolesByCustomerId(customer.Id); return customerRoles?.Any(role => role.SystemName == "Registered") ?? false; } private async Task EnsureBillingAddressAsync(Customer customer) { if (customer.BillingAddressId != null) { return; } var address = new Address { ZipPostalCode = customer.ZipPostalCode, City = customer.City, Address1 = customer.StreetAddress, Address2 = customer.StreetAddress2, CountryId = customer.CountryId > 0 ? customer.CountryId : null, StateProvinceId = customer.StateProvinceId > 0 ? customer.StateProvinceId : null, PhoneNumber = customer.Phone, Company = customer.Company, FirstName = customer.FirstName, LastName = customer.LastName, Email = customer.Email, County = customer.County }; await _addressService.InsertAddressAsync(address); await _dbContext.AddCustomerAddressMappingAsync(customer.Id, address.Id); customer.BillingAddressId = address.Id; } private async Task SynchronizeTaxInformationAsync(Customer customer) { string attributesXml = customer.CustomCustomerAttributesXML; string taxId = null; if (!string.IsNullOrWhiteSpace(attributesXml)) { var doc = XDocument.Parse(attributesXml); taxId = doc.Descendants("CustomerAttribute") .FirstOrDefault(el => (int?)el.Attribute("ID") == 1) // your TaxId attribute ID ?.Descendants("Value") .FirstOrDefault() ?.Value; } if (!string.IsNullOrWhiteSpace(taxId) && string.IsNullOrWhiteSpace(customer.VatNumber)) { customer.VatNumber = taxId; } else if (string.IsNullOrWhiteSpace(taxId) && !string.IsNullOrWhiteSpace(customer.VatNumber)) { await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync( customer.Id, "TaxId", customer.VatNumber); } _dbContext.Customers.Update(customer, false); } } }