481 lines
21 KiB
C#
481 lines
21 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|