diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs index 7a5a6eb..7881a9e 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs @@ -5,19 +5,30 @@ using FruitBank.Common.Interfaces; using FruitBank.Common.Server.Interfaces; using FruitBank.Common.SignalRs; using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using Nop.Core.Domain.Customers; using Nop.Core.Domain.Orders; +using Nop.Core.Domain.Payments; +using Nop.Core.Domain.Shipping; +using Nop.Core.Domain.Tax; using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; using Nop.Plugin.Misc.FruitBankPlugin.Factories; using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders; +using Nop.Services.Catalog; using Nop.Services.Common; +using Nop.Services.Customers; using Nop.Services.Messages; using Nop.Services.Orders; +using Nop.Services.Payments; using Nop.Services.Security; using Nop.Web.Areas.Admin.Controllers; using Nop.Web.Areas.Admin.Factories; using Nop.Web.Areas.Admin.Models.Orders; using Nop.Web.Framework; using Nop.Web.Framework.Mvc.Filters; +using System.Text.Json.Serialization; +using System.Xml; +using System.Xml.Serialization; namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers { @@ -31,9 +42,11 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers private readonly IPermissionService _permissionService; private readonly IGenericAttributeService _genericAttributeService; private readonly INotificationService _notificationService; + private readonly ICustomerService _customerService; + private readonly IProductService _productService; // ... other dependencies - public CustomOrderController(IOrderService orderService, IOrderModelFactory orderModelFactory, ICustomOrderSignalREndpointServer customOrderSignalREndpoint, IPermissionService permissionService, IGenericAttributeService genericAttributeService, INotificationService notificationService) + public CustomOrderController(IOrderService orderService, IOrderModelFactory orderModelFactory, ICustomOrderSignalREndpointServer customOrderSignalREndpoint, IPermissionService permissionService, IGenericAttributeService genericAttributeService, INotificationService notificationService, ICustomerService customerService, IProductService productService) { _orderService = orderService; _orderModelFactory = orderModelFactory as CustomOrderModelFactory; @@ -41,6 +54,8 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers _permissionService = permissionService; _genericAttributeService = genericAttributeService; _notificationService = notificationService; + _customerService = customerService; + _productService = productService; // ... initialize other deps } @@ -134,6 +149,377 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers return RedirectToAction("Edit", "Order", new { id = model.OrderId }); } + [HttpPost] + //[CheckPermission(StandardPermission.Orders.ORDERS_CREATE)] + public virtual async Task Create(int customerId, string orderProductsJson) + { + if (!await _permissionService.AuthorizeAsync(StandardPermission.Orders.ORDERS_CREATE_EDIT_DELETE)) + return AccessDeniedView(); + + // Validate customer + var customer = await _customerService.GetCustomerByIdAsync(customerId); + if (customer == null) + return RedirectToAction("List"); + + // Parse products + var orderProducts = string.IsNullOrEmpty(orderProductsJson) + ? new List() + : JsonConvert.DeserializeObject>(orderProductsJson); + + // Create order + var order = new Order + { + OrderGuid = Guid.NewGuid(), + CustomOrderNumber = "", + CustomerId = customerId, + CustomerLanguageId = customer.LanguageId ?? 1, + CustomerTaxDisplayType = TaxDisplayType.IncludingTax, + CustomerIp = string.Empty, + OrderStatusId = (int)OrderStatus.Pending, + PaymentStatusId = (int)PaymentStatus.Pending, + ShippingStatusId = (int)ShippingStatus.ShippingNotRequired, + CreatedOnUtc = DateTime.UtcNow, + BillingAddressId = customer.BillingAddressId ?? 0, + ShippingAddressId = customer.ShippingAddressId + }; + + await _orderService.InsertOrderAsync(order); + + // Add order items + foreach (var item in orderProducts) + { + var product = await _productService.GetProductByIdAsync(item.Id); + if (product != null) + { + var orderItem = new OrderItem + { + OrderId = order.Id, + ProductId = item.Id, + Quantity = item.Quantity, + UnitPriceInclTax = item.Price, + UnitPriceExclTax = item.Price, + PriceInclTax = item.Price * item.Quantity, + PriceExclTax = item.Price * item.Quantity, + OriginalProductCost = product.ProductCost, + AttributeDescription = string.Empty, + AttributesXml = string.Empty, + DiscountAmountInclTax = 0, + DiscountAmountExclTax = 0 + }; + + await _orderService.InsertOrderItemAsync(orderItem); + } + } + + return RedirectToAction("Edit", new { id = order.Id }); + } + + public class OrderProductItem + { + public int Id { get; set; } + public string Name { get; set; } + public string Sku { get; set; } + public int Quantity { get; set; } + public decimal Price { get; set; } + } + + //private static OrderItem CreateOrderItem(ProductToAuctionMapping productToAuction, Order order, decimal orderTotal) + //{ + // return new OrderItem + // { + // ProductId = productToAuction.ProductId, + // OrderId = order.Id, + // OrderItemGuid = Guid.NewGuid(), + // PriceExclTax = orderTotal, + // PriceInclTax = orderTotal, + // UnitPriceExclTax = orderTotal, + // UnitPriceInclTax = orderTotal, + // Quantity = productToAuction.ProductAmount, + // }; + //} + + //private static Order CreateOrder(ProductToAuctionMapping productToAuction, decimal orderTotal, Customer customer, Address billingAddress, int storeId, Dictionary customValues) + //{ + // return new Order + // { + // BillingAddressId = billingAddress.Id, + // CreatedOnUtc = DateTime.UtcNow, + // CurrencyRate = 1, + // CustomOrderNumber = productToAuction.AuctionId + "/" + productToAuction.SortIndex, + // CustomValuesXml = SerializeCustomValuesToXml(customValues), + // CustomerCurrencyCode = "HUF", + // CustomerId = productToAuction.WinnerCustomerId, + // CustomerLanguageId = 2, + // CustomerTaxDisplayType = TaxDisplayType.IncludingTax, + // OrderGuid = Guid.NewGuid(), + // OrderStatus = OrderStatus.Pending, + // OrderTotal = orderTotal, + // PaymentStatus = PaymentStatus.Pending, + // PaymentMethodSystemName = "Payments.CheckMoneyOrder", + // ShippingStatus = ShippingStatus.ShippingNotRequired, + // StoreId = storeId, + // VatNumber = customer.VatNumber, + // CustomerIp = customer.LastIpAddress, + // OrderSubtotalExclTax = orderTotal, + // OrderSubtotalInclTax = orderTotal + // }; + //} + + private static OrderNote CreateOrderNote(Order order, string note) + { + return new OrderNote + { + CreatedOnUtc = order.CreatedOnUtc, + DisplayToCustomer = true, + OrderId = order.Id, + Note = note + }; + } + + private static string SerializeCustomValuesToXml(Dictionary sourceDictionary) + { + ArgumentNullException.ThrowIfNull(sourceDictionary); + + if (!sourceDictionary.Any()) + return null; + + var ds = new DictionarySerializer(sourceDictionary); + var xs = new XmlSerializer(typeof(DictionarySerializer)); + + using var textWriter = new StringWriter(); + using (var xmlWriter = XmlWriter.Create(textWriter)) + { + xs.Serialize(xmlWriter, ds); + } + + var result = textWriter.ToString(); + return result; + } + + + [HttpGet] // Change from [HttpPost] to [HttpGet] + [CheckPermission(StandardPermission.Customers.CUSTOMERS_VIEW)] + public virtual async Task CustomerSearchAutoComplete(string term) + { + if (string.IsNullOrWhiteSpace(term) || term.Length < 2) + return Json(new List()); + + const int maxResults = 15; + + // Search by email (contains) + var customersByEmail = await _customerService.GetAllCustomersAsync( + email: term, + pageIndex: 0, + pageSize: maxResults); + + // Search by first name (contains) + var customersByFirstName = await _customerService.GetAllCustomersAsync( + firstName: term, + pageIndex: 0, + pageSize: maxResults); + + // Search by last name (contains) + var customersByLastName = await _customerService.GetAllCustomersAsync( + lastName: term, + pageIndex: 0, + pageSize: maxResults); + + // Combine and deduplicate results + var allCustomers = customersByEmail + .Union(customersByFirstName) + .Union(customersByLastName) + .DistinctBy(c => c.Id) + .Take(maxResults) + .ToList(); + + var result = new List(); + foreach (var customer in allCustomers) + { + var fullName = await _customerService.GetCustomerFullNameAsync(customer); + var displayText = !string.IsNullOrEmpty(customer.Email) + ? $"{customer.Email} ({fullName})" + : fullName; + + result.Add(new + { + label = displayText, + value = customer.Id + }); + } + + return Json(result); + } + + [HttpGet] + [CheckPermission(StandardPermission.Catalog.PRODUCTS_VIEW)] + public virtual async Task ProductSearchAutoComplete(string term) + { + if (string.IsNullOrWhiteSpace(term) || term.Length < 2) + return Json(new List()); + + const int maxResults = 15; + + // Search products by name or SKU + var products = await _productService.SearchProductsAsync( + keywords: term, + pageIndex: 0, + pageSize: maxResults); + + var result = new List(); + foreach (var product in products) + { + result.Add(new + { + label = product.Name, + value = product.Id, + sku = product.Sku, + price = product.Price + }); + } + + return Json(result); + } + + + //[HttpPost] + //public async Task CreateInvoice(int orderId) + //{ + // try + // { + // var order = await _orderService.GetOrderByIdAsync(orderId); + // if (order == null) + // return Json(new { success = false, message = "Order not found" }); + + // var billingAddress = await _customerService.GetCustomerBillingAddressAsync(order.Customer); + // if (billingAddress == null) + // return Json(new { success = false, message = "Billing address not found" }); + + // var country = await _countryService.GetCountryByAddressAsync(billingAddress); + // var countryCode = country?.TwoLetterIsoCode ?? "HU"; + + // // Create invoice request + // var invoiceRequest = new InvoiceCreateRequest + // { + // VevoNev = $"{billingAddress.FirstName} {billingAddress.LastName}", + // VevoIrsz = billingAddress.ZipPostalCode ?? "", + // VevoTelep = billingAddress.City ?? "", + // VevoOrszag = countryCode, + // VevoUtcaHsz = $"{billingAddress.Address1} {billingAddress.Address2}".Trim(), + // SzamlatombID = 1, // Configure this based on your setup + // SzamlaKelte = DateTime.Now, + // TeljesitesKelte = DateTime.Now, + // Hatarido = DateTime.Now.AddDays(15), // 15 days payment term + // Devizanem = order.CustomerCurrencyCode, + // FizetesiMod = order.PaymentMethodSystemName, + // Felretett = false, + // Proforma = false, + // Email = billingAddress.Email, + // Telefon = billingAddress.PhoneNumber + // }; + + // // Add order items + // var orderItems = await _orderService.GetOrderItemsAsync(order.Id); + // foreach (var item in orderItems) + // { + // var product = await _productService.GetProductByIdAsync(item.ProductId); + + // invoiceRequest.AddItem(new InvoiceItem + // { + // TetelNev = product?.Name ?? "Product", + // AfaSzoveg = "27%", // Configure VAT rate as needed + // Brutto = true, + // EgysegAr = item.UnitPriceInclTax, + // Mennyiseg = item.Quantity, + // MennyisegEgyseg = "db", + // CikkSzam = product?.Sku + // }); + // } + + // // Create invoice via API + // var response = await _innVoiceApiService.CreateInvoiceAsync(invoiceRequest); + + // if (response.IsSuccess) + // { + // // TODO: Save invoice details to your database for future reference + // // You might want to create a custom table to store: + // // - OrderId + // // - InnVoice TableId + // // - Invoice Number + // // - PDF URL + // // - Created Date + + // return Json(new + // { + // success = true, + // message = "Invoice created successfully", + // data = new + // { + // tableId = response.TableId, + // invoiceNumber = response.Sorszam, + // sorszam = response.Sorszam, + // printUrl = response.PrintUrl + // } + // }); + // } + // else + // { + // return Json(new + // { + // success = false, + // message = $"InnVoice API Error: {response.Message}" + // }); + // } + // } + // catch (Exception ex) + // { + // return Json(new + // { + // success = false, + // message = $"Error: {ex.Message}" + // }); + // } + //} + + //[HttpGet] + //public async Task GetInvoiceStatus(int orderId) + //{ + // try + // { + // // TODO: Retrieve invoice details from your database + // // This is a placeholder - you need to implement actual storage/retrieval + + // // Example: var invoiceData = await _yourInvoiceService.GetByOrderIdAsync(orderId); + // // if (invoiceData != null) + // // { + // // return Json(new + // // { + // // success = true, + // // data = new + // // { + // // tableId = invoiceData.TableId, + // // invoiceNumber = invoiceData.InvoiceNumber, + // // sorszam = invoiceData.InvoiceNumber, + // // printUrl = invoiceData.PrintUrl + // // } + // // }); + // // } + + // return Json(new + // { + // success = false, + // message = "No invoice found for this order" + // }); + // } + // catch (Exception ex) + // { + // return Json(new + // { + // success = false, + // message = $"Error: {ex.Message}" + // }); + // } + //} + } } diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs index dbfaf58..be958ef 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs @@ -186,6 +186,20 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers return Json(model); } + [HttpGet] + public async Task GetAllPartners() + { + if (!await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL)) + return AccessDeniedView(); + + // Mock data for now + var model = await _dbContext.Partners.GetAll().ToListAsync(); + var valami = model; + //model. = await _dbContext.GetShippingDocumentsByShippingIdAsync(shippingId); + return Json(model); + } + + [HttpPost] [RequestSizeLimit(10485760)] // 10MB @@ -240,7 +254,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers //if (file.Length > 0 && file.ContentType == "application/pdf") if (file.Length > 0) { - if (!file.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase)){ + if (file.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase)){ try { // Open the PDF from the IFormFile's stream directly in memory @@ -282,18 +296,18 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers return StatusCode(500, $"Error processing PDF file: {ex.Message}"); } } - else + else //read from image { try { - // Open the PDF from the IFormFile's stream directly in memory + // Open the Image from the IFormFile's stream directly in memory using (var stream = file.OpenReadStream()) { try { // ✅ Use the service we implemented earlier - pdfText = await _openAIApiService.AnalyzePdfAsync(stream, file.FileName, "Please extract all readable text from this PDF."); + pdfText = await _openAIApiService.AnalyzePdfAsync(stream, file.FileName, "Please extract all readable text from this image."); } catch (Exception aiEx) { @@ -319,7 +333,6 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers } - string analysisPrompt = "Extract the document identification number from this document, determine the type of the " + "document IN ENGLISH from the available list, and return them as JSON: documentNumber, documentType. " + $"Available filetypes: {nameof(DocumentType.Invoice)}, {nameof(DocumentType.ShippingDocument)} , {nameof(DocumentType.OrderConfirmation)}, {nameof(DocumentType.Unknown)}" + @@ -342,9 +355,11 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers ShippingDocumentToFiles shippingDocumentToFiles = new ShippingDocumentToFiles { ShippingDocumentId = shippingDocumentId, - FilesId = dbFile.Id + FilesId = dbFile.Id, + DocumentType = extractedMetaData.DocumentType != null ? (DocumentType)Enum.Parse(typeof(DocumentType), extractedMetaData.DocumentType) : DocumentType.Unknown }; + Console.WriteLine(shippingDocumentToFiles.DocumentType); await _dbContext.ShippingDocumentToFiles.InsertAsync(shippingDocumentToFiles); // - IF WE DON'T HAVE PARTNERID ALREADY: read partner information @@ -425,7 +440,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers // Analyze PDF with AI to extract structured data var aiAnalysis = await _aiCalculationService.GetOpenAIPDFAnalysisFromText( pdfText.ToString(), - "Extract the following information from this shipping document and return as JSON: documentDate, recipientName, senderName, invoiceNumber, totalAmount, itemCount, notes. If a field is not found, return null for that field." + "You work for FruitBank. Extract the following information from this shipping document and return as JSON: documentDate, recipientName, senderName, invoiceNumber, totalAmount, itemCount, notes. If a field is not found, return null for that field." ); // Parse AI response (assuming it returns JSON) diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/List.cshtml b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/List.cshtml index a518030..b8d4ee6 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/List.cshtml +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/List.cshtml @@ -12,680 +12,950 @@ @using static Nop.Services.Common.NopLinksDefaults @{ - //page title - ViewBag.PageTitle = T("Admin.Orders").Text; - //active menu item (system name) - NopHtml.SetActiveMenuItemSystemName("Orders"); + //page title + ViewBag.PageTitle = T("Admin.Orders").Text; + //active menu item (system name) + NopHtml.SetActiveMenuItemSystemName("Orders"); } @{ - const string hideSearchBlockAttributeName = "OrdersPage.HideSearchBlock"; - var hideSearchBlock = await genericAttributeService.GetAttributeAsync(await workContext.GetCurrentCustomerAsync(), hideSearchBlockAttributeName); + const string hideSearchBlockAttributeName = "OrdersPage.HideSearchBlock"; + var hideSearchBlock = await genericAttributeService.GetAttributeAsync(await workContext.GetCurrentCustomerAsync(), hideSearchBlockAttributeName); } @if (Model.LicenseCheckModel.BlockPages != true) { -
-
-

- @T("Admin.Orders") -

-
-
- - - -
- -
- - - -
- @await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.OrderListButtons, additionalData = Model }) -
-
-
-
-
-
- +
+
-
+
+ +
+ -
- + @{ + var gridModel = new DataTablesModel + { + Name = "orders-grid", + UrlRead = new DataUrl("OrderList", "CustomOrder", null), + SearchButtonId = "search-orders", + Length = Model.PageSize, + LengthMenu = Model.AvailablePageSizes, + FooterCallback = !Model.IsLoggedInAsVendor ? "ordersfootercallback" : null, + FooterColumns = !Model.IsLoggedInAsVendor ? 10 : 0, + Filters = new List + { + new FilterParameter(nameof(Model.StartDate), typeof(DateTime?)), + new FilterParameter(nameof(Model.EndDate), typeof(DateTime?)), + new FilterParameter(nameof(Model.OrderStatusIds)), + new FilterParameter(nameof(Model.PaymentStatusIds)), + new FilterParameter(nameof(Model.ShippingStatusIds)), + new FilterParameter(nameof(Model.StoreId)), + new FilterParameter(nameof(Model.VendorId)), + new FilterParameter(nameof(Model.WarehouseId)), + new FilterParameter(nameof(Model.BillingEmail)), + new FilterParameter(nameof(Model.BillingPhone)), + new FilterParameter(nameof(Model.BillingLastName)), + new FilterParameter(nameof(Model.BillingCountryId)), + new FilterParameter(nameof(Model.PaymentMethodSystemName)), + new FilterParameter(nameof(Model.ProductId)), + new FilterParameter(nameof(Model.OrderNotes)) + } + }; + gridModel.ColumnCollection = new List + { + new ColumnProperty(nameof(OrderModel.Id)) + { + IsMasterCheckBox = true, + Render = new RenderCheckBox("checkbox_orders"), + ClassName = NopColumnClassDefaults.CenterAll, + Width = "50" + }, + new ColumnProperty(nameof(OrderModel.CustomOrderNumber)) + { + Title = T("Admin.Orders.Fields.CustomOrderNumber").Text, + Width = "80" + } + }; + gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModelExtended.IsMeasured)) + { + Title = T("Admin.Orders.Fields.IsMeasured").Text, + Width = "100", + Render = new RenderCustom("renderColumnIsMeasurable"), + ClassName = NopColumnClassDefaults.CenterAll + }); + gridModel.ColumnCollection.Add(new ColumnProperty(nameof(IOrderDto.DateOfReceipt)) + { + Title = T("Admin.Orders.Fields.PickupDate").Text, + Width = "100", + Render = new RenderCustom("renderColumnPickupDateAndTime"), + ClassName = NopColumnClassDefaults.CenterAll + }); - @{ - var gridModel = new DataTablesModel - { - Name = "orders-grid", - UrlRead = new DataUrl("OrderList", "CustomOrder", null), - SearchButtonId = "search-orders", - Length = Model.PageSize, - LengthMenu = Model.AvailablePageSizes, - FooterCallback = !Model.IsLoggedInAsVendor ? "ordersfootercallback" : null, - FooterColumns = !Model.IsLoggedInAsVendor ? 10 : 0, - Filters = new List - { - new FilterParameter(nameof(Model.StartDate), typeof(DateTime?)), - new FilterParameter(nameof(Model.EndDate), typeof(DateTime?)), - new FilterParameter(nameof(Model.OrderStatusIds)), - new FilterParameter(nameof(Model.PaymentStatusIds)), - new FilterParameter(nameof(Model.ShippingStatusIds)), - new FilterParameter(nameof(Model.StoreId)), - new FilterParameter(nameof(Model.VendorId)), - new FilterParameter(nameof(Model.WarehouseId)), - new FilterParameter(nameof(Model.BillingEmail)), - new FilterParameter(nameof(Model.BillingPhone)), - new FilterParameter(nameof(Model.BillingLastName)), - new FilterParameter(nameof(Model.BillingCountryId)), - new FilterParameter(nameof(Model.PaymentMethodSystemName)), - new FilterParameter(nameof(Model.ProductId)), - new FilterParameter(nameof(Model.OrderNotes)) - } - }; - gridModel.ColumnCollection = new List - { - new ColumnProperty(nameof(OrderModel.Id)) - { - IsMasterCheckBox = true, - Render = new RenderCheckBox("checkbox_orders"), - ClassName = NopColumnClassDefaults.CenterAll, - Width = "50" - }, - new ColumnProperty(nameof(OrderModel.CustomOrderNumber)) - { - Title = T("Admin.Orders.Fields.CustomOrderNumber").Text, - Width = "80" - } - }; - gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModelExtended.IsMeasurable)) - { - Title = T("Admin.Orders.Fields.ToBeMeasured").Text, - Width = "100", - Render = new RenderCustom("renderColumnIsMeasurable"), - ClassName = NopColumnClassDefaults.CenterAll - }); - gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModelExtended.IsMeasured)) - { - Title = T("Admin.Orders.Fields.IsMeasured").Text, - Width = "100", - Render = new RenderCustom("renderColumnIsMeasurable"), - ClassName = NopColumnClassDefaults.CenterAll - }); - gridModel.ColumnCollection.Add(new ColumnProperty(nameof(IOrderDto.DateOfReceipt)) - { - Title = T("Admin.Orders.Fields.PickupDate").Text, - Width = "100", - //Render = new RenderCustom("renderColumnPickupDateAndTime"), - Render = new RenderDate(), - ClassName = NopColumnClassDefaults.CenterAll - }); + //a vendor does not have access to this functionality + if (!Model.IsLoggedInAsVendor) + { + gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.OrderStatus)) + { + Title = T("Admin.Orders.Fields.OrderStatus").Text, + Width = "100", + Render = new RenderCustom("renderColumnOrderStatus") + }); + } + gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.PaymentStatus)) + { + Title = T("Admin.Orders.Fields.PaymentStatus").Text, + Width = "150" + }); + //a vendor does not have access to this functionality + if (!Model.IsLoggedInAsVendor) + { + gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.ShippingStatus)) + { + Title = T("Admin.Orders.Fields.ShippingStatus").Text, + Width = "150" + }); + } + gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.CustomerEmail)) + { + Title = T("Admin.Orders.Fields.Customer").Text, + Render = new RenderCustom("renderColumnCustomer") + }); + gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.StoreName)) + { + Title = T("Admin.Orders.Fields.Store").Text, + Width = "100", + Visible = (await storeService.GetAllStoresAsync()).Count > 1 + }); + gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.CreatedOn)) + { + Title = T("Admin.Orders.Fields.CreatedOn").Text, + Width = "120", + Render = new RenderDate() + }); + //a vendor does not have access to this functionality + if (!Model.IsLoggedInAsVendor) + { + gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.OrderTotal)) + { + Title = T("Admin.Orders.Fields.OrderTotal").Text, + Width = "100", + }); + } + gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.Id)) + { + Title = T("Admin.Common.View").Text, + Width = "50", + ClassName = NopColumnClassDefaults.Button, + Render = new RenderButtonView(new DataUrl("~/Admin/Order/Edit")) + }); + var orderSummaryColumnNumber = 8; + } + @await Html.PartialAsync("Table", gridModel) - //a vendor does not have access to this functionality - if (!Model.IsLoggedInAsVendor) - { - gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.OrderStatus)) - { - Title = T("Admin.Orders.Fields.OrderStatus").Text, - Width = "100", - Render = new RenderCustom("renderColumnOrderStatus") - }); - } - gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.PaymentStatus)) - { - Title = T("Admin.Orders.Fields.PaymentStatus").Text, - Width = "150" - }); - //a vendor does not have access to this functionality - if (!Model.IsLoggedInAsVendor) - { - gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.ShippingStatus)) - { - Title = T("Admin.Orders.Fields.ShippingStatus").Text, - Width = "150" - }); - } - gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.CustomerEmail)) - { - Title = T("Admin.Orders.Fields.Customer").Text, - Render = new RenderCustom("renderColumnCustomer") - }); - gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.StoreName)) - { - Title = T("Admin.Orders.Fields.Store").Text, - Width = "100", - Visible = (await storeService.GetAllStoresAsync()).Count > 1 - }); - gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.CreatedOn)) - { - Title = T("Admin.Orders.Fields.CreatedOn").Text, - Width = "120", - Render = new RenderDate() - }); - //a vendor does not have access to this functionality - if (!Model.IsLoggedInAsVendor) - { - gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.OrderTotal)) - { - Title = T("Admin.Orders.Fields.OrderTotal").Text, - Width = "100", - }); - } - gridModel.ColumnCollection.Add(new ColumnProperty(nameof(OrderModel.Id)) - { - Title = T("Admin.Common.View").Text, - Width = "50", - ClassName = NopColumnClassDefaults.Button, - Render = new RenderButtonView(new DataUrl("~/Admin/Order/Edit")) - }); - var orderSummaryColumnNumber = 8; - } - @await Html.PartialAsync("Table", gridModel) + -
-
-
-
-
-
-
+ $(function() { + $("#@Html.IdFor(model => model.GoDirectlyToCustomOrderNumber)").keydown( + function(event) { + if (event.keyCode === 13) { + $("#go-to-order-by-number").trigger("click"); + return false; + } + }); + }); + function ordersfootercallback(tfoot, data, start, end, display) { + //update order totals summary + var postData = { + StartDate: $('#@Html.IdFor(model => model.StartDate)').val(), + EndDate: $('#@Html.IdFor(model => model.EndDate)').val(), + OrderStatusIds: $('#@Html.IdFor(model => model.OrderStatusIds)').val(), + PaymentStatusIds: $('#@Html.IdFor(model => model.PaymentStatusIds)').val(), + ShippingStatusIds: $('#@Html.IdFor(model => model.ShippingStatusIds)').val(), + StoreId: $('#@Html.IdFor(model => model.StoreId)').val(), + VendorId: $('#@Html.IdFor(model => model.VendorId)').val(), + WarehouseId: $('#@Html.IdFor(model => model.WarehouseId)').val(), + BillingEmail: $('#@Html.IdFor(model => model.BillingEmail)').val(), + BillingPhone: $('#@Html.IdFor(model => model.BillingPhone)').val(), + BillingLastName: $('#@Html.IdFor(model => model.BillingLastName)').val(), + BillingCountryId: $('#@Html.IdFor(model => model.BillingCountryId)').val(), + PaymentMethodSystemName: $('#@Html.IdFor(model => model.PaymentMethodSystemName)').val(), + ProductId: $('#@Html.IdFor(model => model.ProductId)').val(), + OrderNotes: $('#@Html.IdFor(model => model.OrderNotes)').val() + }; + addAntiForgeryToken(postData); + + $.ajax({ + cache: false, + type: "POST", + url: "@(Url.Action("ReportAggregates", "Order"))", + data: postData, + success: function (data, textStatus, jqXHR) { + if (data) { + for (var key in data) { + var reportSummary = '
@T("Admin.Orders.Report.Summary").Text
' + + '
@T("Admin.Orders.Report.Profit").Text ' + data['AggregatorProfit'] +'
' + + '
@T("Admin.Orders.Report.Shipping").Text ' + data['AggregatorShipping'] + '
' + + '
@T("Admin.Orders.Report.Tax").Text ' + data['AggregatorTax'] + '
' + + '
@T("Admin.Orders.Report.Total").Text ' + data['AggregatorTotal'] + '
' + var orderTotalsColumn = $('#orders-grid').DataTable().column(@(orderSummaryColumnNumber)); + $(orderTotalsColumn.footer()).html(reportSummary); + } + } + } + }); + } + + + + + + + + } @*export selected (XML). We don't use GET approach because it's limited to 2K-4K chars and won't work for large number of entities*@
- +
@*export selected (Excel). We don't use GET approach because it's limited to 2K-4K chars and won't work for large number of entities*@
- +
@*Print packaging slips selected (XML). We don't use GET approach because it's limited to 2K-4K chars and won't work for large number of entities*@
- +
@*import orders form*@ +@*create new order form*@ + + + + + \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/ShippingDocumentGridComponent.cshtml b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/ShippingDocumentGridComponent.cshtml index f3a41a6..6b76abb 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/ShippingDocumentGridComponent.cshtml +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/ShippingDocumentGridComponent.cshtml @@ -24,14 +24,22 @@ }) .Columns(c => { c.Add().DataField("Id").AllowEditing(false); - c.Add().DataField("Partner.Name").AllowEditing(false); + c.Add().DataField("PartnerId") + .AllowEditing(true) + .Lookup(lookup => lookup + .DataSource(d => d.Mvc().Controller("ManagementPage").LoadAction("GetAllPartners").Key("Id")) + .ValueExpr("Id") + .DisplayExpr("Name") + ) + .EditCellTemplate(new TemplateName("DropDownBoxTemplate")) + .Width(150); c.Add() .Caption("Items in order") .DataType(GridColumnDataType.Number) .CalculateCellValue("calculateItemsCount").AllowEditing(false); - c.Add().DataField("PartnerId"); + @* c.Add().DataField("PartnerId"); *@ c.Add().DataField("DocumentIdNumber"); - c.Add().DataField("IsAllMeasured"); + c.Add().DataField("IsAllMeasured").AllowEditing(false); c.Add() .Caption("Completed") .DataType(GridColumnDataType.Boolean) @@ -54,8 +62,10 @@ ); }); }) - .MasterDetail(md => md.Enabled(true).Template(new TemplateName("masterDetailTemplate"))) - ) + .MasterDetail(md => md.Enabled(true).Template(new TemplateName("masterDetailTemplate")) + ) +) + @using (Html.DevExtreme().NamedTemplate("masterDetailTemplate")) @@ -108,6 +118,40 @@ } } +@using(Html.DevExtreme().NamedTemplate("DropDownBoxTemplate")) { + @(Html.DevExtreme().DropDownBox() + .DataSource(d => d.Mvc().Controller("ManagementPage").LoadAction("GetAllPartners").Key("Id")) + .Value(new JS("value")) + .ValueExpr("Id") + .InputAttr("aria-label", "Partner") + .DisplayExpr("Name") + .DropDownOptions(options => options.Width(500)) + .Option("setValue", new JS("setValue")) + .ContentTemplate(new TemplateName("ContentTemplate")) + ) +} + +@using(Html.DevExtreme().NamedTemplate("ContentTemplate")) { + @(Html.DevExtreme().DataGrid() + .DataSource(d => d.Mvc().Controller("ManagementPage").LoadAction("GetAllPartners").Key("Id")) + .RemoteOperations(true) + .Height(250) + .Columns(c => { + c.Add().DataField("Name"); + c.Add().DataField("Country"); + c.Add().DataField("TaxId"); + }) + .Scrolling(s => s.Mode(GridScrollingMode.Virtual)) + .HoverStateEnabled(true) + .Selection(s => s.Mode(SelectionMode.Single)) + .SelectedRowKeys(new JS("component.option('value') !== undefined && component.option('value') !== null ? [component.option('value')] : []")) + .FocusedRowEnabled(true) + .FocusedRowKey(new JS("component.option('value')")) + .OnContextMenuPreparing("function(e) { e.items = [] }") + .OnSelectionChanged("function(e) { onPartnerSelectionChanged(e, component) }") + ) +} + \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Infrastructure/RouteProvider.cs b/Nop.Plugin.Misc.AIPlugin/Infrastructure/RouteProvider.cs index c37686b..ebd5829 100644 --- a/Nop.Plugin.Misc.AIPlugin/Infrastructure/RouteProvider.cs +++ b/Nop.Plugin.Misc.AIPlugin/Infrastructure/RouteProvider.cs @@ -131,6 +131,11 @@ public class RouteProvider : IRouteProvider name: "Plugin.FruitBank.Admin.Orders.SaveOrderAttributes", pattern: "Admin/CustomOrder/SaveOrderAttributes", defaults: new { controller = "CustomOrder", action = "SaveOrderAttributes", area = AreaNames.ADMIN }); + + endpointRouteBuilder.MapControllerRoute( + name: "Plugin.FruitBank.Admin.Orders.CustomerSearchAutoComplete", + pattern: "Admin/CustomOrder/CustomerSearchAutoComplete", + defaults: new { controller = "CustomOrder", action = "CustomerSearchAutoComplete", area = AreaNames.ADMIN }); } /// diff --git a/Nop.Plugin.Misc.AIPlugin/Services/EventConsumer.cs b/Nop.Plugin.Misc.AIPlugin/Services/EventConsumer.cs index a593d02..67d5201 100644 --- a/Nop.Plugin.Misc.AIPlugin/Services/EventConsumer.cs +++ b/Nop.Plugin.Misc.AIPlugin/Services/EventConsumer.cs @@ -1,8 +1,10 @@ -using System.Linq; -using FruitBank.Common.Interfaces; +using FruitBank.Common.Interfaces; +using Microsoft.AspNetCore.Http; using Nop.Core; using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Orders; +using Nop.Core.Events; +using Nop.Plugin.Misc.FruitBankPlugin.Models; using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders; using Nop.Services.Catalog; using Nop.Services.Common; @@ -13,10 +15,11 @@ using Nop.Services.Plugins; using Nop.Web.Framework.Events; using Nop.Web.Framework.Menu; using Nop.Web.Models.Sitemap; +using System.Linq; namespace Nop.Plugin.Misc.FruitBankPlugin.Services { - public class EventConsumer : BaseAdminMenuCreatedEventConsumer, IConsumer, IConsumer + public class EventConsumer : BaseAdminMenuCreatedEventConsumer, IConsumer, IConsumer>, IConsumer { private readonly IGenericAttributeService _genericAttributeService; private readonly IProductService _productService; @@ -27,6 +30,8 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services private readonly IStoreContext _storeContext; private readonly IAdminMenu _adminMenu; private readonly ILocalizationService _localizationService; + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly FruitBankAttributeService _fruitBankAttributeService; public EventConsumer( IGenericAttributeService genericAttributeService, @@ -38,7 +43,9 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services IWorkContext workContext, IStoreContext storeContext, IAdminMenu adminMenu, - ILocalizationService localizationService) : base(pluginManager) + ILocalizationService localizationService, + IHttpContextAccessor httpContextAccessor, + FruitBankAttributeService fruitBankAttributeService) : base(pluginManager) { _genericAttributeService = genericAttributeService; _productService = productService; @@ -49,6 +56,8 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services _storeContext = storeContext; _adminMenu = adminMenu; _localizationService = localizationService; + _httpContextAccessor = httpContextAccessor; + _fruitBankAttributeService = fruitBankAttributeService; } protected override string PluginSystemName => "Misc.FruitBankPlugin"; @@ -120,6 +129,39 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services } } + public async Task HandleEventAsync(EntityUpdatedEvent eventMessage) + { + await SaveOrderCustomAttributesAsync(eventMessage.Entity); + } + + + private async Task SaveOrderCustomAttributesAsync(Order order) + { + if (order == null) return; + + var form = _httpContextAccessor.HttpContext?.Request?.Form; + 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 dateOfReceipt = form[nameof(IOrderDto.DateOfReceipt)]; + + await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync(order.Id, nameof(IOrderDto.DateOfReceipt), DateTime.Parse(dateOfReceipt)); + } + + } + + + public async Task HandleEventAsync(AdminMenuCreatedEvent eventMessage) { var rootNode = eventMessage.RootMenuItem; diff --git a/Nop.Plugin.Misc.AIPlugin/Views/OrderAttributes.cshtml b/Nop.Plugin.Misc.AIPlugin/Views/OrderAttributes.cshtml index 9090a3d..217b16f 100644 --- a/Nop.Plugin.Misc.AIPlugin/Views/OrderAttributes.cshtml +++ b/Nop.Plugin.Misc.AIPlugin/Views/OrderAttributes.cshtml @@ -1,6 +1,43 @@ @using Nop.Plugin.Misc.FruitBankPlugin.Models.Orders @model OrderAttributesModel + +
+
+ + InnVoice Invoice Management +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ +
@@ -16,7 +53,6 @@
-
@@ -26,7 +62,6 @@
-