From 7e7a6e098246c10131e5d4e30e30749de1418000 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 10 Oct 2025 22:59:23 +0200 Subject: [PATCH] edit and update ismeasurable, netweight, incomingQuantity --- .../Controllers/ManagementPageController.cs | 6 +- .../Admin/Models/Catalog/ProductModel.cs | 21 ++++++ .../ProductAttributesViewComponent.cs | 73 +++++++++++++++++++ .../EventConsumers/FruitBankEventConsumer.cs | 55 +++++++++++++- Nop.Plugin.Misc.AIPlugin/FruitBankPlugin.cs | 17 ++++- .../Models/ProductAttributesModel.cs | 19 +++++ .../Nop.Plugin.Misc.FruitBankPlugin.csproj | 6 ++ .../Views/ProductAttributes.cshtml | 41 +++++++++++ .../Views/ProductList.cshtml | 54 ++++++++++++++ 9 files changed, 286 insertions(+), 6 deletions(-) create mode 100644 Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/Catalog/ProductModel.cs create mode 100644 Nop.Plugin.Misc.AIPlugin/Components/ProductAttributesViewComponent.cs create mode 100644 Nop.Plugin.Misc.AIPlugin/Models/ProductAttributesModel.cs create mode 100644 Nop.Plugin.Misc.AIPlugin/Views/ProductAttributes.cshtml create mode 100644 Nop.Plugin.Misc.AIPlugin/Views/ProductList.cshtml diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs index a8138a3..86a7c7c 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/ManagementPageController.cs @@ -234,13 +234,13 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers // - 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 } - if (partnerId == null) + if (partnerId != null) { - string partnerAnalysisPrompt = "Extract the partner information from this document, and return them as JSON: name, taxId, certificationNumber, postalCode, country, state, county, city, street. " + + string partnerAnalysisPrompt = "Extract the sender information from this document, and return them as JSON: name, taxId, certificationNumber, postalCode, country, state, county, city, street. " + "If you can't find information of any of these, return null value for that field."; //here I can start preparing the file entity - var partnerAnalyzis = await _aiCalculationService.GetOpenAIPDFAnalysisFromText(pdfText.ToString(), analysisPrompt); + var partnerAnalyzis = await _aiCalculationService.GetOpenAIPDFAnalysisFromText(pdfText.ToString(), partnerAnalysisPrompt); var extractedPartnerData = ParsePartnerDataAIResponse(partnerAnalyzis); if (extractedPartnerData.Name != null) diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/Catalog/ProductModel.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/Catalog/ProductModel.cs new file mode 100644 index 0000000..0e24930 --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Models/Catalog/ProductModel.cs @@ -0,0 +1,21 @@ +using Nop.Web.Areas.Admin.Models.Catalog; +using Nop.Web.Framework.Models; +using Nop.Web.Framework.Mvc.ModelBinding; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Models.Catalog +{ + public partial record ProductModel : BaseNopEntityModel + { + // ... existing properties ... + + [NopResourceDisplayName("Admin.Catalog.Products.Fields.IsMeasurable")] + public bool IsMeasurable { get; set; } + + // ... rest of your model ... + } +} diff --git a/Nop.Plugin.Misc.AIPlugin/Components/ProductAttributesViewComponent.cs b/Nop.Plugin.Misc.AIPlugin/Components/ProductAttributesViewComponent.cs new file mode 100644 index 0000000..06ba9bb --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Components/ProductAttributesViewComponent.cs @@ -0,0 +1,73 @@ +// File: Plugins/YourCompany.ProductAttributes/Components/ProductAttributesViewComponent.cs + +using FruitBank.Common.Interfaces; +using Microsoft.AspNetCore.Mvc; +using Nop.Core; +using Nop.Core.Domain.Catalog; +using Nop.Plugin.Misc.FruitBankPlugin.Models; +using Nop.Services.Common; +using Nop.Web.Areas.Admin.Models.Catalog; +using Nop.Web.Framework.Components; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Components +{ + [ViewComponent(Name = "ProductAttributes")] + public class ProductAttributesViewComponent : NopViewComponent + { + private const string NET_WEIGHT_KEY = nameof(IMeasuringAttributeValues.NetWeight); + private const string GROSS_WEIGHT_KEY = nameof(IMeasuringAttributeValues.GrossWeight); + private const string IS_MEASURABLE_KEY = nameof(IMeasuringAttributeValues.IsMeasurable); + + private readonly IGenericAttributeService _genericAttributeService; + private readonly IWorkContext _workContext; + private readonly IStoreContext _storeContext; + + public ProductAttributesViewComponent( + IGenericAttributeService genericAttributeService, + IWorkContext workContext, + IStoreContext storeContext) + { + _genericAttributeService = genericAttributeService; + _workContext = workContext; + _storeContext = storeContext; + } + + public async Task InvokeAsync(string widgetZone, object additionalData) + { + + + if (additionalData is not ProductModel product) + return Content(""); + + var model = new ProductAttributesModel + { + ProductId = product.Id + }; + + //get store scope + var storeScope = await _storeContext.GetCurrentStoreAsync(); + + + if (product.Id > 0) + { + // Load existing values + var dbProduct = new Core.Domain.Catalog.Product { Id = product.Id }; + + //var dbMesaurable = await _genericAttributeService.GetAttributeAsync(dbProduct, IS_MEASURABLE_KEY, storeScope.Id); + //var dbNetWeight = await _genericAttributeService.GetAttributeAsync(dbProduct, NET_WEIGHT_KEY, storeScope.Id); + //var dbIncomingQuantity = await _genericAttributeService.GetAttributeAsync(dbProduct, "IncomingQuantity", storeScope.Id); + + model.IsMeasurable = await _genericAttributeService + .GetAttributeAsync(dbProduct, IS_MEASURABLE_KEY, storeScope.Id); + + model.NetWeight = await _genericAttributeService + .GetAttributeAsync(dbProduct, NET_WEIGHT_KEY, storeScope.Id); + + model.IncomingQuantity = await _genericAttributeService + .GetAttributeAsync(dbProduct, "IncomingQuantity", storeScope.Id); + } + + return View("~/Plugins/Misc.FruitBankPlugin/Views/ProductAttributes.cshtml", model); + } + } +} diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/EventConsumers/FruitBankEventConsumer.cs b/Nop.Plugin.Misc.AIPlugin/Domains/EventConsumers/FruitBankEventConsumer.cs index aadf6c2..6c7f39b 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/EventConsumers/FruitBankEventConsumer.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/EventConsumers/FruitBankEventConsumer.cs @@ -1,5 +1,6 @@ using AyCode.Core.Loggers; using AyCode.Interfaces.Entities; +using DevExpress.XtraPrinting.Native; using FruitBank.Common.Entities; using FruitBank.Common.Interfaces; using FruitBank.Common.Loggers; @@ -18,12 +19,15 @@ using Nop.Services.Events; namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.EventConsumers; -public class FruitBankEventConsumer(IHttpContextAccessor httpContextAccessor, FruitBankDbContext ctx, FruitBankAttributeService fruitBankAttributeService, IStoreContext storeContext, IEnumerable logWriters) : +public class FruitBankEventConsumer(IHttpContextAccessor httpContextAccessor, FruitBankDbContext ctx, FruitBankAttributeService fruitBankAttributeService, IStoreContext storeContext, IEnumerable logWriters, IGenericAttributeService genericAttributeService) : MgEventConsumer(httpContextAccessor, logWriters), IConsumer>, IConsumer> { public override async Task HandleEventAsync(EntityUpdatedEvent eventMessage) { var product = eventMessage.Entity; + + await SaveCustomAttributesAsync(eventMessage.Entity); + var isMeasurableProduct = await fruitBankAttributeService.IsMeasurableEntityAsync(product.Id); var shippingItems = await ctx.ShippingItems.Table @@ -37,6 +41,55 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAccessor, Fr await base.HandleEventAsync(eventMessage); } + + public async Task HandleEventAsync(EntityInsertedEvent eventMessage) + { + await SaveCustomAttributesAsync(eventMessage.Entity); + } + + private async Task SaveCustomAttributesAsync(Product product) + { + if (product == null) + return; + + var form = httpContextAccessor.HttpContext?.Request?.Form; + if (form == null || !form.Any()) + return; + + var isMeasurable = form["IsMeasurable"].ToString().Contains("true"); + + // Save IsMeasurable + if (form.ContainsKey("IsMeasurable")) + { + await genericAttributeService.SaveAttributeAsync(product, "IsMeasurable", isMeasurable); + //Akkor ez kell? - Á. + //await fruitBankAttributeService.InsertOrUpdateMeasuringAttributeValuesAsync(product.Id, 0, 0, isMeasurable, false); + } + + // Save NetWeight + if (form.ContainsKey("NetWeight")) + { + var netWeightStr = form["NetWeight"].ToString(); + if (!string.IsNullOrWhiteSpace(netWeightStr) && decimal.TryParse(netWeightStr, out var netWeight)) + { + await genericAttributeService.SaveAttributeAsync(product, "NetWeight", netWeight); + + //await fruitBankAttributeService.InsertOrUpdateMeasuringAttributeValuesAsync(product.Id, 0, 0, , false); + } + } + + // Save IncomingQuantity + if (form.ContainsKey("IncomingQuantity")) + { + var incomingQtyStr = form["IncomingQuantity"].ToString(); + if (!string.IsNullOrWhiteSpace(incomingQtyStr) && int.TryParse(incomingQtyStr, out var incomingQuantity)) + { + await genericAttributeService.SaveAttributeAsync(product, "IncomingQuantity", incomingQuantity); + } + } + } + + public async Task HandleEventAsync(EntityInsertedEvent eventMessage) { Logger.Info($"HandleEventAsync EntityInsertedEvent; id: {eventMessage.Entity.Id}"); diff --git a/Nop.Plugin.Misc.AIPlugin/FruitBankPlugin.cs b/Nop.Plugin.Misc.AIPlugin/FruitBankPlugin.cs index 043578a..6104a13 100644 --- a/Nop.Plugin.Misc.AIPlugin/FruitBankPlugin.cs +++ b/Nop.Plugin.Misc.AIPlugin/FruitBankPlugin.cs @@ -84,7 +84,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin public Task> GetWidgetZonesAsync() { - return Task.FromResult>(new List { PublicWidgetZones.ProductBoxAddinfoBefore, PublicWidgetZones.ProductDetailsBottom }); + return Task.FromResult>(new List { PublicWidgetZones.ProductBoxAddinfoBefore, PublicWidgetZones.ProductDetailsBottom, AdminWidgetZones.ProductDetailsBlock }); } //public string GetWidgetViewComponentName(string widgetZone) @@ -128,7 +128,20 @@ namespace Nop.Plugin.Misc.FruitBankPlugin var zones = GetWidgetZonesAsync().Result; - return zones.Any(widgetZone.Equals) ? typeof(ProductAIWidgetViewComponent) : null; + if (zones.Any(widgetZone.Equals)) + { + if (widgetZone == PublicWidgetZones.ProductBoxAddinfoBefore || widgetZone == PublicWidgetZones.ProductDetailsBottom) + { + return zones.Any(widgetZone.Equals) ? typeof(ProductAIWidgetViewComponent) : null; + } + else if (widgetZone == AdminWidgetZones.ProductDetailsBlock) + { + return zones.Any(widgetZone.Equals) ? typeof(ProductAttributesViewComponent) : null; + } + } + + return null; + } } } diff --git a/Nop.Plugin.Misc.AIPlugin/Models/ProductAttributesModel.cs b/Nop.Plugin.Misc.AIPlugin/Models/ProductAttributesModel.cs new file mode 100644 index 0000000..8be1872 --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Models/ProductAttributesModel.cs @@ -0,0 +1,19 @@ +using Nop.Web.Framework.Models; +using Nop.Web.Framework.Mvc.ModelBinding; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Models +{ + public record ProductAttributesModel : BaseNopModel + { + public int ProductId { get; set; } + + [NopResourceDisplayName("Plugins.YourCompany.ProductAttributes.Fields.IsMeasurable")] + public bool IsMeasurable { get; set; } + + [NopResourceDisplayName("Plugins.YourCompany.ProductAttributes.Fields.NetWeight")] + public decimal? NetWeight { get; set; } + + [NopResourceDisplayName("Plugins.YourCompany.ProductAttributes.Fields.IncomingQuantity")] + public int? IncomingQuantity { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj b/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj index b157f5a..41014e9 100644 --- a/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj +++ b/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj @@ -605,6 +605,12 @@ Always + + Always + + + Always + Always diff --git a/Nop.Plugin.Misc.AIPlugin/Views/ProductAttributes.cshtml b/Nop.Plugin.Misc.AIPlugin/Views/ProductAttributes.cshtml new file mode 100644 index 0000000..e8574ed --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Views/ProductAttributes.cshtml @@ -0,0 +1,41 @@ +@* File: Plugins/Nop.Plugin.YourCompany.ProductAttributes/Views/ProductCustomAttributes.cshtml *@ + +@model Nop.Plugin.Misc.FruitBankPlugin.Models.ProductAttributesModel + +
+
+ + Custom Product Attributes +
+
+
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ + +
+
+
+
\ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Views/ProductList.cshtml b/Nop.Plugin.Misc.AIPlugin/Views/ProductList.cshtml new file mode 100644 index 0000000..ac914c3 --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Views/ProductList.cshtml @@ -0,0 +1,54 @@ +@* File: Plugins/YourCompany.ProductAttributes/Views/ProductList.cshtml *@ +@* This view component will inject into the product list page *@ + + + + +