diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs index 7881a9e..72ac2c1 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/CustomOrderController.cs @@ -1,9 +1,11 @@ -using AyCode.Services.SignalRs; +using AyCode.Core.Loggers; +using AyCode.Services.SignalRs; using FruitBank.Common.Dtos; using FruitBank.Common.Entities; using FruitBank.Common.Interfaces; using FruitBank.Common.Server.Interfaces; using FruitBank.Common.SignalRs; +using Mango.Nop.Core.Loggers; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Nop.Core.Domain.Customers; @@ -36,6 +38,8 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers [AuthorizeAdmin] public class CustomOrderController : BaseAdminController, ICustomOrderSignalREndpointServer { + private readonly FruitBankDbContext _dbContext; + private readonly IOrderService _orderService; private readonly CustomOrderModelFactory _orderModelFactory; private readonly ICustomOrderSignalREndpointServer _customOrderSignalREndpoint; @@ -46,8 +50,13 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers private readonly IProductService _productService; // ... other dependencies - public CustomOrderController(IOrderService orderService, IOrderModelFactory orderModelFactory, ICustomOrderSignalREndpointServer customOrderSignalREndpoint, IPermissionService permissionService, IGenericAttributeService genericAttributeService, INotificationService notificationService, ICustomerService customerService, IProductService productService) + private readonly ILogger _logger; + + public CustomOrderController(FruitBankDbContext fruitBankDbContext, IOrderService orderService, IOrderModelFactory orderModelFactory, ICustomOrderSignalREndpointServer customOrderSignalREndpoint, IPermissionService permissionService, IGenericAttributeService genericAttributeService, INotificationService notificationService, ICustomerService customerService, IProductService productService, IEnumerable logWriters) { + _logger = new Logger(logWriters.ToArray()); + + _dbContext = fruitBankDbContext; _orderService = orderService; _orderModelFactory = orderModelFactory as CustomOrderModelFactory; _customOrderSignalREndpoint = customOrderSignalREndpoint; @@ -100,10 +109,10 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers //return _customOrderService. var orderListModel = await _orderModelFactory.PrepareOrderListModelExtendedAsync(searchModel); - Console.WriteLine($"Total: {orderListModel.RecordsTotal}, Data Count: {orderListModel.Data.Count()}"); + _logger.Debug($"Total: {orderListModel.RecordsTotal}, Data Count: {orderListModel.Data.Count()}"); foreach (var item in orderListModel.Data.Take(3)) { - Console.WriteLine($"Order: {item.Id}, {item.CustomOrderNumber}"); + _logger.Debug($"Order: {item.Id}, {item.CustomOrderNumber}"); } return orderListModel; @@ -158,13 +167,10 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers // Validate customer var customer = await _customerService.GetCustomerByIdAsync(customerId); - if (customer == null) - return RedirectToAction("List"); + if (customer == null) return RedirectToAction("List"); // Parse products - var orderProducts = string.IsNullOrEmpty(orderProductsJson) - ? new List() - : JsonConvert.DeserializeObject>(orderProductsJson); + var orderProducts = string.IsNullOrEmpty(orderProductsJson) ? [] : JsonConvert.DeserializeObject>(orderProductsJson); // Create order var order = new Order @@ -175,43 +181,55 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers CustomerLanguageId = customer.LanguageId ?? 1, CustomerTaxDisplayType = TaxDisplayType.IncludingTax, CustomerIp = string.Empty, - OrderStatusId = (int)OrderStatus.Pending, - PaymentStatusId = (int)PaymentStatus.Pending, - ShippingStatusId = (int)ShippingStatus.ShippingNotRequired, + OrderStatus = OrderStatus.Pending, + PaymentStatus = PaymentStatus.Pending, + ShippingStatus = ShippingStatus.ShippingNotRequired, CreatedOnUtc = DateTime.UtcNow, BillingAddressId = customer.BillingAddressId ?? 0, ShippingAddressId = customer.ShippingAddressId }; - await _orderService.InsertOrderAsync(order); + var productDtosById = await _dbContext.ProductDtos.GetAllByIds(orderProducts.Select(op => op.Id)).ToDictionaryAsync(p => p.Id, prodDto => prodDto); - // Add order items - foreach (var item in orderProducts) + var transactionSuccess = await _dbContext.TransactionSafeAsync(async _ => { - var product = await _productService.GetProductByIdAsync(item.Id); - if (product != null) + await _orderService.InsertOrderAsync(order); + + foreach (var item in orderProducts) { - var orderItem = new OrderItem + //var product = await _productService.GetProductByIdAsync(item.Id); + //if (product != null) + + if (productDtosById.TryGetValue(item.Id, out var product)) { - 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 - }; + 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); + await _orderService.InsertOrderItemAsync(orderItem); + } + else _logger.Error($"(productDtosById.TryGetValue(item.Id, out var product) == false); {item}"); } - } - return RedirectToAction("Edit", new { id = order.Id }); + return true; + }); + + if (transactionSuccess) return RedirectToAction("Edit", new { id = order.Id }); + + _logger.Error($"(transactionSuccess == false)"); + return RedirectToAction("Error", new { id = order.Id }); } public class OrderProductItem @@ -221,6 +239,11 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers public string Sku { get; set; } public int Quantity { get; set; } public decimal Price { get; set; } + + public override string ToString() + { + return $"{nameof(OrderProductItem)} [Id: {Id}; Name: {Name}; Sku: {Sku}; Quantity: {Quantity}; Price: {Price}]"; + } } //private static OrderItem CreateOrderItem(ProductToAuctionMapping productToAuction, Order order, decimal orderTotal) diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs index be958ef..7d0eb92 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs @@ -1,6 +1,8 @@ -using DevExpress.Pdf.Native; +using AyCode.Core.Loggers; +using DevExpress.Pdf.Native; using FruitBank.Common; using FruitBank.Common.Entities; +using Mango.Nop.Core.Loggers; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -26,8 +28,12 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers protected readonly AICalculationService _aiCalculationService; protected readonly OpenAIApiService _openAIApiService; - public ManagementPageController(IPermissionService permissionService, FruitBankDbContext fruitBankDbContext, AICalculationService aiCalculationService, OpenAIApiService openAIApiService) + private readonly ILogger _logger; + + public ManagementPageController(IPermissionService permissionService, FruitBankDbContext fruitBankDbContext, AICalculationService aiCalculationService, OpenAIApiService openAIApiService, IEnumerable logWriters) { + _logger = new Logger(logWriters.ToArray()); + _permissionService = permissionService; _dbContext = fruitBankDbContext; _aiCalculationService = aiCalculationService; @@ -220,7 +226,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers // - do we have partnerId - if so, we already have at least one doecument uploaded earlier if (partnerId.HasValue) { - Console.WriteLine($"Associated with Partner ID: {partnerId.Value}"); + _logger.Debug($"Associated with Partner ID: {partnerId.Value}"); //let's get the partner var partner = await _dbContext.Partners.GetByIdAsync(partnerId.Value); @@ -240,7 +246,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers var dbFile = new Files(); string pdfText = ""; - Console.WriteLine($"Received file: {fileName} for Document ID: {shippingDocumentId}, content type: {file.ContentType}"); + _logger.Detail($"Received file: {fileName} for Document ID: {shippingDocumentId}, content type: {file.ContentType}"); if (!file.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase) && !file.ContentType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase)) return Json(new { success = false, errorMessage = "Only PDF or jpg files are allowed" }); @@ -285,7 +291,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers } // For demonstration, let's just log the extracted text - Console.WriteLine($"Extracted text from {file.FileName}: {pdfText}"); + _logger.Detail($"Extracted text from {file.FileName}: {pdfText}"); } } @@ -316,7 +322,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers } // For demonstration, let's just log the extracted text - Console.WriteLine($"Extracted text from {file.FileName}: {pdfText}"); + _logger.Detail($"Extracted text from {file.FileName}: {pdfText}"); } } @@ -329,7 +335,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers } } //we should have some kind of text now - Console.WriteLine(pdfText); + _logger.Detail(pdfText); } @@ -350,18 +356,26 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers dbFile.FileName = extractedMetaData.DocumentNumber; } - await _dbContext.Files.InsertAsync(dbFile); - filesList.Add(dbFile); - ShippingDocumentToFiles shippingDocumentToFiles = new ShippingDocumentToFiles + var transactionSuccess = await _dbContext.TransactionSafeAsync(async _ => { - ShippingDocumentId = shippingDocumentId, - FilesId = dbFile.Id, - DocumentType = extractedMetaData.DocumentType != null ? (DocumentType)Enum.Parse(typeof(DocumentType), extractedMetaData.DocumentType) : DocumentType.Unknown - }; + await _dbContext.Files.InsertAsync(dbFile); + filesList.Add(dbFile); - Console.WriteLine(shippingDocumentToFiles.DocumentType); + var shippingDocumentToFiles = new ShippingDocumentToFiles + { + ShippingDocumentId = shippingDocumentId, + FilesId = dbFile.Id, + DocumentType = extractedMetaData.DocumentType != null ? (DocumentType)Enum.Parse(typeof(DocumentType), extractedMetaData.DocumentType) : DocumentType.Unknown + }; + + _logger.Detail(shippingDocumentToFiles.DocumentType.ToString()); + + await _dbContext.ShippingDocumentToFiles.InsertAsync(shippingDocumentToFiles); + return true; + }); + + if (!transactionSuccess) _logger.Error($"(transactionSuccess == false)"); - await _dbContext.ShippingDocumentToFiles.InsertAsync(shippingDocumentToFiles); // - IF WE DON'T HAVE PARTNERID ALREADY: read partner information // (check if all 3 refers to the same partner) // save partner information to partners table { Id, Name, TaxId, CertificationNumber, PostalCode, Country, State, County, City, Street } @@ -376,24 +390,24 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers if (extractedPartnerData.Name != null) { - Console.WriteLine("AI Analysis Partner Result:"); - Console.WriteLine(extractedPartnerData.Name); + _logger.Detail("AI Analysis Partner Result:"); + _logger.Detail(extractedPartnerData.Name); } if (extractedPartnerData.TaxId != null) { - Console.WriteLine(extractedPartnerData.TaxId); + _logger.Detail(extractedPartnerData.TaxId); } if (extractedPartnerData.Country != null) { - Console.WriteLine(extractedPartnerData.Country); + _logger.Detail(extractedPartnerData.Country); } if (extractedPartnerData.State != null) { - Console.WriteLine(extractedPartnerData.State); + _logger.Detail(extractedPartnerData.State); } } @@ -418,7 +432,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers } catch (Exception ex) { - Console.WriteLine($"Error saving file: {ex}"); + _logger.Error($"Error saving file: {ex.Message}", ex); //return Json(new { success = false, errorMessage = ex.Message }); return BadRequest("No files were uploaded."); } @@ -447,13 +461,13 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers var extractedData = ParseShippingDocumentAIResponse(aiAnalysis); //TODO: Save document record to database - Console.WriteLine("AI Analysis Result:"); - Console.WriteLine(extractedData.RecipientName); - Console.WriteLine(extractedData.SenderName); - Console.WriteLine(extractedData.InvoiceNumber); - Console.WriteLine(extractedData.TotalAmount); - Console.WriteLine(extractedData.ItemCount); - Console.WriteLine(extractedData.Notes); + _logger.Detail("AI Analysis Result:"); + _logger.Detail(extractedData.RecipientName); + _logger.Detail(extractedData.SenderName); + _logger.Detail(extractedData.InvoiceNumber); + _logger.Detail(extractedData.TotalAmount.ToString()); + _logger.Detail(extractedData.ItemCount.ToString()); + _logger.Detail(extractedData.Notes); var documentId = 1; // Replace with: savedDocument.Id @@ -492,7 +506,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers } catch (Exception ex) { - Console.WriteLine($"Error uploading file: {ex}"); + _logger.Error($"Error uploading file: {ex.Message}", ex); //return Json(new { success = false, errorMessage = ex.Message }); return BadRequest("No files were uploaded."); } @@ -531,7 +545,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers // // Log or process the file and its associated ID. // // For demonstration, let's just return a success message. - // Console.WriteLine($"Received file: {fileName} for Document ID: {shippingDocumentId}"); + // _logger.Detail($"Received file: {fileName} for Document ID: {shippingDocumentId}"); // } // // Return a success response. The DevExtreme FileUploader expects a 200 OK status.