Mango.Nop.Plugins/Nop.Plugin.Misc.AIPlugin/Services/EventConsumer.cs

481 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<EntityUpdatedEvent<Customer>>, IConsumer<EntityInsertedEvent<Customer>>, IConsumer<OrderPlacedEvent>, IConsumer<EntityUpdatedEvent<Order>>, IConsumer<AdminMenuCreatedEvent>
{
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<CustomerAttribute, CustomerAttributeValue> _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<IPlugin> pluginManager,
IWorkContext workContext,
IStoreContext storeContext,
IAdminMenu adminMenu,
ILocalizationService localizationService,
IHttpContextAccessor httpContextAccessor,
IAddressService addressService,
FruitBankAttributeService fruitBankAttributeService,
FruitBankDbContext dbContext,
IAttributeParser<CustomerAttribute, CustomerAttributeValue> 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<Nop.Core.Domain.Customers.Customer, DateTime?>(order.CustomerId, pendingKey, storeId);
if (pendingDateTime.HasValue)
{
await _fruitBankAttributeService
.InsertOrUpdateGenericAttributeAsync<Nop.Core.Domain.Orders.Order, DateTime>(
order.Id, nameof(IOrderDto.DateOfReceipt), pendingDateTime.Value, storeId);
// Clean up — the value has been transferred to the order
await _fruitBankAttributeService
.DeleteGenericAttributeAsync<Nop.Core.Domain.Customers.Customer>(order.CustomerId, pendingKey, storeId);
Console.WriteLine($"[EventConsumer] OrderPlaced #{order.Id} DateOfReceipt set to {pendingDateTime.Value:u}");
}
}
public async Task HandleEventAsync(EntityUpdatedEvent<Order> 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<Order, bool>(eventMessage.Entity.Id, "OrderAuditedNotificationSent");
if (!alreadySent)
{
await _fruitBankNotificationService
.SendOrderAuditedCustomerNotificationAsync(eventMessage.Entity, orderDto.IsMeasurable);
await _fruitBankAttributeService
.InsertOrUpdateGenericAttributeAsync<Order, bool>(
eventMessage.Entity.Id, "OrderAuditedNotificationSent", true);
}
}
else if (orderDto.MeasuringStatus == MeasuringStatus.Started)
{
var alreadySent = await _fruitBankAttributeService
.GetGenericAttributeValueAsync<Order, bool>(eventMessage.Entity.Id, "OrderStartedNotificationSent");
if (!alreadySent)
{
await _fruitBankNotificationService
.SendOrderStartedCustomerNotificationAsync(eventMessage.Entity, orderDto.IsMeasurable);
await _fruitBankAttributeService
.InsertOrUpdateGenericAttributeAsync<Order, bool>(
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<bool>(form[nameof(IMeasurable.IsMeasurable)].ToString());
// await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Order, bool>(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, DateTime>(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<AdminMenuItem>
{
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<Customer> eventMessage)
{
await ProcessCustomerEventAsync(eventMessage?.Entity);
}
public async Task HandleEventAsync(EntityUpdatedEvent<Customer> 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, string>(
customer.Id,
"TaxId",
customer.VatNumber);
}
_dbContext.Customers.Update(customer, false);
}
}
}