From 0bee8979b7659bfd665722112cc209df1d4797fb Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 19 Oct 2025 13:57:55 +0200 Subject: [PATCH] Documenntype? OrderId? --- .../Controllers/CustomOrderController.cs | 305 +++++++++++++++++- .../Controllers/ManagementPageController.cs | 8 +- .../Areas/Admin/Views/Order/List.cshtml | 219 ++++++++++++- .../Views/OrderAttributes.cshtml | 144 ++++++++- 4 files changed, 651 insertions(+), 25 deletions(-) diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs index df4306e..7881a9e 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs @@ -5,6 +5,8 @@ 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; @@ -12,16 +14,21 @@ 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 { @@ -36,9 +43,10 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers 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, ICustomerService customerService) + public CustomOrderController(IOrderService orderService, IOrderModelFactory orderModelFactory, ICustomOrderSignalREndpointServer customOrderSignalREndpoint, IPermissionService permissionService, IGenericAttributeService genericAttributeService, INotificationService notificationService, ICustomerService customerService, IProductService productService) { _orderService = orderService; _orderModelFactory = orderModelFactory as CustomOrderModelFactory; @@ -47,6 +55,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers _genericAttributeService = genericAttributeService; _notificationService = notificationService; _customerService = customerService; + _productService = productService; // ... initialize other deps } @@ -141,23 +150,30 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers } [HttpPost] - public virtual async Task Create(int customerId) + //[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 exists + // Validate customer var customer = await _customerService.GetCustomerByIdAsync(customerId); if (customer == null) return RedirectToAction("List"); - // Create new empty order + // 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)customer.TaxDisplayType, + CustomerTaxDisplayType = TaxDisplayType.IncludingTax, CustomerIp = string.Empty, OrderStatusId = (int)OrderStatus.Pending, PaymentStatusId = (int)PaymentStatus.Pending, @@ -169,10 +185,117 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers await _orderService.InsertOrderAsync(order); - // Redirect to edit page + // 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)] @@ -227,6 +350,176 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers 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 1acca9b..be958ef 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs @@ -254,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 @@ -296,7 +296,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers return StatusCode(500, $"Error processing PDF file: {ex.Message}"); } } - else + else //read from image { try { @@ -359,6 +359,8 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers 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 // (check if all 3 refers to the same partner) @@ -438,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 5784df9..b8d4ee6 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/List.cshtml +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/Order/List.cshtml @@ -701,15 +701,16 @@ @*create new order form*@