diff --git a/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs b/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs index bfb74fb..4a9ab00 100644 --- a/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs @@ -190,11 +190,18 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers { _logger.Detail($"GetMeasuringUsers invoked"); - var customers = await ctx.GetCustormersBySystemRoleName(FruitBankConst.MeasuringRoleSystemName).Select(c => new CustomerDto(c)).ToListAsync(); - + var customers = await ctx.GetCustomersBySystemRoleName(FruitBankConst.MeasuringRoleSystemName).Select(c => new CustomerDto(c)).ToListAsync(); return customers; //.ToModelDto(); } + [SignalR(SignalRTags.GetCustomerRolesByCustomerId)] + public async Task> GetCustomerRolesByCustomerId(int customerId) + { + _logger.Detail($"GetCustomerRolesByCustomerId invoked; customerId: {customerId}"); + + return await ctx.GetCustomerRolesByCustomerId(customerId).ToListAsync(); + } + [SignalR(SignalRTags.GetProductDtos)] public async Task> GetProductDtos() { diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs index dd87605..ba54c5b 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs @@ -1,24 +1,32 @@ -using AyCode.Core.Loggers; +#nullable enable +using AyCode.Core.Loggers; +using AyCode.Utils.Extensions; using FruitBank.Common.Entities; using FruitBank.Common.Interfaces; using FruitBank.Common.Models; +using FruitBank.Common.Server; +using LinqToDB; +using LinqToDB.Common; using Mango.Nop.Core.Loggers; using Mango.Nop.Core.Repositories; +using Nop.Core; using Nop.Core.Caching; +using Nop.Core.ComponentModel; using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Customers; using Nop.Data; using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer.Interfaces; +using Nop.Plugin.Misc.FruitBankPlugin.Services; using Nop.Services.Catalog; -using NUglify.Helpers; +using Nop.Services.Common; using System.Transactions; -using LinqToDB; -using Nop.Core.ComponentModel; namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet, IShippingDbSet, IShippingItemDbSet, IShippingDocumentDbSet { + private readonly FruitBankAttributeService _fruitBankAttributeService; + private readonly IStoreContext _storeContext; private readonly IProductService _productService; private readonly IStaticCacheManager _staticCacheManager; @@ -33,16 +41,19 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet public IRepository CustomerRoleMappings { get; set; } - public FruitBankDbContext(INopDataProvider dataProvider, PartnerDbTable partnerDbTable, ShippingDbTable shippingDbTable, ShippingItemDbTable shippingItemDbTable, + public FruitBankDbContext(INopDataProvider dataProvider, ILockService lockService, FruitBankAttributeService fruitBankAttributeService, IStoreContext storeContext, + PartnerDbTable partnerDbTable, ShippingDbTable shippingDbTable, ShippingItemDbTable shippingItemDbTable, ShippingDocumentDbTable shippingDocumentDbTable, IProductService productService, IStaticCacheManager staticCacheManager, IRepository productRepository, IRepository customerRepository, IRepository customerCustomerRoleMappingRepository, IRepository customerRoleRepository, - IEnumerable logWriters) : base(dataProvider, logWriters) + IEnumerable logWriters) : base(dataProvider, lockService, logWriters) { + _storeContext = storeContext; _productService = productService; _staticCacheManager = staticCacheManager; + _fruitBankAttributeService = fruitBankAttributeService; Partners = partnerDbTable; Shippings = shippingDbTable; @@ -66,7 +77,7 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet return query; } - public IQueryable GetCustormersBySystemRoleName(string systemRoleName) + public IQueryable GetCustomersBySystemRoleName(string systemRoleName) { if (systemRoleName.IsNullOrWhiteSpace()) throw new ArgumentException("systemRoleName.IsNullOrWhiteSpace()", nameof(systemRoleName)); @@ -80,135 +91,150 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet return query.Distinct().OrderBy(o => o.Username); } + public IQueryable GetCustomerRolesByCustomerId(int customerId) + { + var query = + from cr in CustomerRoles.Table + join crm in CustomerRoleMappings.Table on cr.Id equals crm.CustomerRoleId + where crm.CustomerId == customerId + select cr; + + return query.Distinct(); + } + public IQueryable GetAllProducts() => Products.Table.Where(p => !p.Deleted).OrderBy(o => o.Name); public Task UpdateMeasuredShippingItemAsync(ShippingItem shippingItem) { - if (!shippingItem.IsMeasurable || shippingItem.IsValidMeasuringValues()) return UpdateShippingItemAsync(shippingItem); + if (shippingItem.IsValidMeasuringValues()) return UpdateShippingItemAsync(shippingItem); Logger.Error("shippingItem.IsMeasurable && !shippingItem.IsValidMeasuringValues()"); return Task.FromResult(false); } - private static readonly ReaderWriterLockSlim _locker = new(LockRecursionPolicy.NoRecursion); - - public async Task UpdateShippingItemAsync(ShippingItem shippingItem) + public Task UpdateShippingItemAsync(ShippingItem shippingItem) { if (shippingItem == null) { Logger.Error("shippingItem == null"); - return await Task.FromResult(false); + return Task.FromResult(false); } - //using (new ReaderWriteLockDisposable(_locker)) - //_locker.EnterWriteLock(); - //try - //{ - using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); + return TransactionSafeAsync(async tr => + { try { //Mi van ha nem jött meg a termék? Nem fogják tudni menteni... - J. - if (shippingItem.MeasuredQuantity <= 0) shippingItem.MeasuredQuantity = null; + Product? product = null; + var productIsMeasurable = false; - if (!shippingItem.IsMeasurable || shippingItem.MeasuredNetWeight <= 0) shippingItem.MeasuredNetWeight = null; - if (!shippingItem.IsMeasurable || shippingItem.MeasuredGrossWeight <= 0) shippingItem.MeasuredGrossWeight = null; - - //Update elÅ‘tt kivesszük a korábbi ShippingItem-et a db-bÅ‘l! - J. - var dbShippingItem = await ShippingItems.GetByIdAsync(shippingItem.Id); - if (dbShippingItem == null) - { - Logger.Error("dbShippingItem == null"); - return await Task.FromResult(false); - } - - Product product = null; if (shippingItem.ProductId > 0) { product = await Products.GetByIdAsync(shippingItem.ProductId); if (product == null) - { - Logger.Error($"shippingItem.ProductId > 0 && product == null; shippingItem.ProductId: {shippingItem.ProductId}"); - return await Task.FromResult(false); - } + throw new Exception($"shippingItem.ProductId > 0 && product == null; shippingItem.ProductId: {shippingItem.ProductId}"); + + productIsMeasurable = await _fruitBankAttributeService.IsMeasurableEntityAsync(product.Id); } + shippingItem.IsMeasurable = productIsMeasurable; + + if (shippingItem.MeasuredQuantity <= 0) shippingItem.MeasuredQuantity = null; + if (!shippingItem.IsMeasurable || shippingItem.MeasuredNetWeight <= 0) shippingItem.MeasuredNetWeight = null; + if (!shippingItem.IsMeasurable || shippingItem.MeasuredGrossWeight <= 0) shippingItem.MeasuredGrossWeight = null; + + //Update elÅ‘tt kivesszük a korábbi ShippingItem-et a db-bÅ‘l! - J. + var dbShippingItem = await ShippingItems.GetByIdAsync(shippingItem.Id); + if (dbShippingItem == null) throw new Exception($"dbShippingItem == null; shippingItem.Id: {shippingItem.Id}"); + shippingItem.IsMeasured = product != null && shippingItem.IsValidMeasuringValues(); - await ShippingItems.UpdateAsync(shippingItem); + await ShippingItems.UpdateAsync(shippingItem, shippingItem.IsMeasured != dbShippingItem.IsMeasured); - //TODO: a measuredweight-eket is! - J. - if (shippingItem.ProductId != dbShippingItem.ProductId || - shippingItem.IsMeasured != dbShippingItem.IsMeasured || shippingItem.IsMeasurable != dbShippingItem.IsMeasurable || - shippingItem.MeasuredQuantity != dbShippingItem.MeasuredQuantity || - shippingItem.MeasuredNetWeight != dbShippingItem.MeasuredNetWeight || shippingItem.MeasuredGrossWeight != dbShippingItem.MeasuredGrossWeight) + if (shippingItem.ProductId == dbShippingItem.ProductId && + shippingItem.IsMeasured == dbShippingItem.IsMeasured && shippingItem.IsMeasurable == dbShippingItem.IsMeasurable && + shippingItem.MeasuredQuantity == dbShippingItem.MeasuredQuantity && + // ReSharper disable once CompareOfFloatsByEqualityOperator + shippingItem.MeasuredNetWeight == dbShippingItem.MeasuredNetWeight && + // ReSharper disable once CompareOfFloatsByEqualityOperator + shippingItem.MeasuredGrossWeight == dbShippingItem.MeasuredGrossWeight) { - var productIdUnchanged = shippingItem.ProductId == dbShippingItem.ProductId; + return true; + } - if (shippingItem.IsMeasured) + var productIdUnchanged = shippingItem.ProductId == dbShippingItem.ProductId; + + if (shippingItem.IsMeasured) + { + product!.StockQuantity += productIdUnchanged ? shippingItem.MeasuredQuantity!.Value - dbShippingItem.MeasuredQuantity.GetValueOrDefault(0) : shippingItem.MeasuredQuantity!.Value; + + if (!await UpdateProductStockQuantityAsync(product, true)) + throw new Exception($"UpdateProductStockQuantity() == false; shippingItem! product.Id: {product.Id}"); + + if (productIsMeasurable) { - product!.StockQuantity += shippingItem.MeasuredQuantity.GetValueOrDefault(0); - - if (!await UpdateProductStockQuantityAsync(product)) + var measuringValues = new MeasuringAttributeValues { - Logger.Error($"UpdateProductStockQuantity() == false; shippingItem! id: {product.Id}"); - return await Task.FromResult(false); - } - } + NetWeight = productIdUnchanged ? shippingItem.MeasuredNetWeight - dbShippingItem.MeasuredNetWeight.GetValueOrDefault(0) : shippingItem.MeasuredNetWeight, + GrossWeight = productIdUnchanged ? shippingItem.MeasuredGrossWeight - dbShippingItem.MeasuredGrossWeight.GetValueOrDefault(0) : shippingItem.MeasuredGrossWeight, + IsMeasurable = shippingItem.IsMeasurable + }; - if (dbShippingItem.IsMeasured) - { - product = await Products.GetByIdAsync(dbShippingItem.ProductId); - - if (product != null) - { - product.StockQuantity -= dbShippingItem.MeasuredQuantity.GetValueOrDefault(0); - - if (!await UpdateProductStockQuantityAsync(product)) - { - Logger.Error($"UpdateProductStockQuantity() == false; dbShippingItem! id: {product.Id}"); - return await Task.FromResult(false); - } - } - else Logger.Warning($"product == null; dbShippingItem.ProductId: {dbShippingItem.ProductId}"); + await _fruitBankAttributeService.InsertOrUpdateMeasuringAttributeValuesAsync(product.Id, measuringValues, true); } } + + if (productIdUnchanged || !dbShippingItem.IsMeasured) return true; + + product = await Products.GetByIdAsync(dbShippingItem.ProductId); + + if (product != null) + { + productIsMeasurable = await _fruitBankAttributeService.IsMeasurableEntityAsync(product.Id); + product.StockQuantity -= dbShippingItem.MeasuredQuantity.GetValueOrDefault(0); + + if (!await UpdateProductStockQuantityAsync(product, true)) + throw new Exception($"UpdateProductStockQuantity() == false; dbShippingItem! product.Id: {product.Id}"); + + if (!productIsMeasurable) return true; + + var measuringValues = new MeasuringAttributeValues(-dbShippingItem.MeasuredNetWeight.GetValueOrDefault(0), -dbShippingItem.MeasuredGrossWeight.GetValueOrDefault(0), dbShippingItem.IsMeasurable); + await _fruitBankAttributeService.InsertOrUpdateMeasuringAttributeValuesAsync(product.Id, measuringValues, true); + + } + else Logger.Warning($"product == null; dbShippingItem.ProductId: {dbShippingItem.ProductId}"); //else //TODO: productIdUnchanged-et lekezelni! - J. + + return true; } catch (Exception ex) { - Logger.Error($"UpdateShippingItemAsync Transaction ERROR! Id: {shippingItem?.Id}", ex); - return await Task.FromResult(false); + throw new Exception($"UpdateShippingItemAsync->TransactionSafeAsync error! shippingItem.Id: {shippingItem.Id}; ex: {ex.Message}", ex); } - - transaction.Complete(); - //} - //finally - //{ - // _locker.ExitWriteLock(); - //} - - return await Task.FromResult(true); + }); } - private async Task UpdateProductStockQuantityAsync(int productId) + + + private async Task UpdateProductStockQuantityAsync(int productId, bool publishEvent) { var product = await Products.GetByIdAsync(productId); - if (product != null) return await UpdateProductStockQuantityAsync(product); + if (product != null) return await UpdateProductStockQuantityAsync(product, publishEvent); Logger.Error($"product == null; id: {productId}"); return await Task.FromResult(false); } - private async Task UpdateProductStockQuantityAsync(Product product) + private async Task UpdateProductStockQuantityAsync(Product product, bool publishEvent) { //Itt mi legyen? RollBack? - J. if (product.StockQuantity < 0) Logger.Error($"product.StockQuantity < 0; Id: {product.Id}; StockQuantity: {product.StockQuantity}"); - await Products.UpdateAsync(product, true); + await Products.UpdateAsync(product, publishEvent); return await Task.FromResult(true); //var updatedRowsCount = await DataProvider.ExecuteNonQueryAsync($"update product set {nameof(Product.StockQuantity)} = {product.StockQuantity} where {nameof(Product.Id)} = {product.Id}"); diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/ShippingDbTable.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/ShippingDbTable.cs index 6614130..d20f7cd 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/ShippingDbTable.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/ShippingDbTable.cs @@ -29,9 +29,16 @@ public class ShippingDbTable : MgDbTableBase } public IQueryable GetAllNotMeasured(bool loadRelations) - => GetAll(loadRelations).Where(s => !s.IsAllMeasured); + => GetAll(loadRelations).Where(s => !s.IsAllMeasured || s.MeasuredDate == null || s.MeasuredDate < DateTime.Now.AddDays(1000)); public Task GetByIdAsync(int id, bool loadRelations) => GetAll(loadRelations).FirstOrDefaultAsync(s => s.Id == id); + + protected override void OnUpdate(Shipping entity) + { + if (entity is { IsAllMeasured: true, MeasuredDate: null }) entity.MeasuredDate = DateTime.Now; + + base.OnUpdate(entity); + } } \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/ShippingItemDbTable.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/ShippingItemDbTable.cs index e06e2a1..142afbd 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/ShippingItemDbTable.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/ShippingItemDbTable.cs @@ -16,8 +16,19 @@ public class ShippingItemDbTable : MgDbTableBase { } - public override IQueryable GetAll() - => base.GetAll(); + protected override void OnUpdate(ShippingItem entity) + { + RoundMeasuredValue(entity); + base.OnUpdate(entity); + } + + protected override void OnInsert(ShippingItem entity) + { + RoundMeasuredValue(entity); + base.OnInsert(entity); + } + + public override IQueryable GetAll() => base.GetAll(); public IQueryable GetAll(bool loadRelations) { @@ -42,4 +53,10 @@ public class ShippingItemDbTable : MgDbTableBase public IQueryable GetAllByShippingDocumentIdAsync(int shippingDocumentId, bool loadRelations) => GetAll(loadRelations).Where(si => si.ShippingDocumentId == shippingDocumentId); + private static void RoundMeasuredValue(ShippingItem shippingItem) + { + if (shippingItem.MeasuredNetWeight.HasValue) shippingItem.MeasuredNetWeight = double.Round(shippingItem.MeasuredNetWeight.Value, 1); + if (shippingItem.MeasuredGrossWeight.HasValue) shippingItem.MeasuredGrossWeight = double.Round(shippingItem.MeasuredGrossWeight.Value, 1); + + } } \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/EventConsumers/FruitBankEventConsumer.cs b/Nop.Plugin.Misc.AIPlugin/Domains/EventConsumers/FruitBankEventConsumer.cs index 1ee6b79..ceb7026 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/EventConsumers/FruitBankEventConsumer.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/EventConsumers/FruitBankEventConsumer.cs @@ -2,26 +2,35 @@ using FruitBank.Common.Entities; using FruitBank.Common.Interfaces; using FruitBank.Common.Loggers; +using FruitBank.Common.Server; using Mango.Nop.Core.Loggers; using Mango.Nop.Services; using Microsoft.AspNetCore.Http; +using Nop.Core; using Nop.Core.Domain.Catalog; using Nop.Core.Events; using Nop.Plugin.Misc.FruitBankPlugin.Controllers; using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; +using Nop.Plugin.Misc.FruitBankPlugin.Services; +using Nop.Services.Common; using Nop.Services.Events; namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.EventConsumers; -public class FruitBankEventConsumer(IHttpContextAccessor httpContextAccessor, FruitBankDbContext ctx, IEnumerable logWriters) : - MgEventConsumer(httpContextAccessor, logWriters), - IConsumer>, - IConsumer> +public class FruitBankEventConsumer(IHttpContextAccessor httpContextAccessor, FruitBankDbContext ctx, FruitBankAttributeService fruitBankAttributeService, IStoreContext storeContext, IEnumerable logWriters) : + MgEventConsumer(httpContextAccessor, logWriters), IConsumer>, IConsumer> { - public override Task HandleEventAsync(EntityUpdatedEvent eventMessage) + public override async Task HandleEventAsync(EntityUpdatedEvent eventMessage) { - - return base.HandleEventAsync(eventMessage); + var product = eventMessage.Entity; + var isMeasurableProduct = await fruitBankAttributeService.IsMeasurableEntityAsync(product.Id); + + var shippingItems = await ctx.ShippingItems.Table + .Where(si => si.ProductId == product.Id && !si.IsMeasured && si.IsMeasurable != isMeasurableProduct) + .ToListAsync(); + + await ctx.ShippingItems.UpdateAsync(shippingItems, false); + await base.HandleEventAsync(eventMessage); } public async Task HandleEventAsync(EntityInsertedEvent eventMessage) @@ -49,7 +58,7 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAccessor, Fr private async Task UpdateShippingDocumentIsAllMeasuredAsync(ShippingItem shippingItem) { - //TODO: where: && IsMeasureable!!!! - J. + //TODO: where: && IsMeasurable!!!! - J. var isAllShippingItemMeasured = ctx.ShippingItems.GetAll(false).Where(si => si.ShippingDocumentId == shippingItem.ShippingDocumentId).All(si => si.IsMeasured); var shippingDocument = await ctx.ShippingDocuments.GetByIdAsync(shippingItem.ShippingDocumentId); diff --git a/Nop.Plugin.Misc.AIPlugin/FruitBankPlugin.cs b/Nop.Plugin.Misc.AIPlugin/FruitBankPlugin.cs index 2cde142..043578a 100644 --- a/Nop.Plugin.Misc.AIPlugin/FruitBankPlugin.cs +++ b/Nop.Plugin.Misc.AIPlugin/FruitBankPlugin.cs @@ -21,7 +21,9 @@ namespace Nop.Plugin.Misc.FruitBankPlugin public class FruitBankPlugin : BasePlugin, IWidgetPlugin { protected readonly IActionContextAccessor _actionContextAccessor; + private readonly ISettingService _settingService; + //private readonly IWebHelper _webHelper; protected readonly IPermissionService _permissionService; protected readonly ILocalizationService _localizationService; @@ -35,9 +37,9 @@ namespace Nop.Plugin.Misc.FruitBankPlugin ISettingService settingService, //IWebHelper webHelper, ILocalizationService localizationService, - IPermissionService permissionService, - IUrlHelperFactory urlHelperFactory, - IAdminMenu adminMenu) + IPermissionService permissionService, + IUrlHelperFactory urlHelperFactory, + IAdminMenu adminMenu) { _actionContextAccessor = actionContextAccessor; _settingService = settingService; @@ -52,8 +54,13 @@ namespace Nop.Plugin.Misc.FruitBankPlugin public override async Task InstallAsync() { //TODO: Add "Measuring" role - FruitBankConst.MeasuringRoleSystemName + //TODO: Add "MeasuringRevisor" role - FruitBankConst.MeasuringRevisorRoleSystemName + + //TODO: Add "IsMeasurable" product attribute - FruitBankConst.IsMeasurableAttributeName //TODO: Add "NeedsToBeMeasured" product attribute if not exists + //TODO: Add unique index to GenericAttribute[EntityId, KeyGroup, Key]???!? ÁTGONDOLNI, mert lehet esetleg lista is a visszaadott, de a nopcommerce kódban felülírja ha azonos key-el vannak! - J. + // Default settings var settings = new FruitBankSettings { diff --git a/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs b/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs index b665582..6b7355b 100644 --- a/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs +++ b/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs @@ -8,6 +8,7 @@ using FruitBank.Common.Interfaces; using FruitBank.Common.Server.Services.Loggers; using FruitBank.Common.Server.Services.SignalRs; using Mango.Nop.Core.Loggers; +using Mango.Nop.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.SignalR; @@ -45,13 +46,15 @@ public class PluginNopStartup : INopStartup }); //register services and interfaces - //services.AddDevExpressControls(); + + services.AddSingleton(); services.AddScoped(); //services.AddScoped(); services.AddScoped(); //services.AddSingleton(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj b/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj index e8f5709..36e5345 100644 --- a/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj +++ b/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj @@ -110,6 +110,9 @@ ..\..\..\..\FruitBankHybridApp\FruitBank.Common.Server\bin\Debug\net9.0\AyCode.Services.Server.dll + + ..\..\..\..\FruitBankHybridApp\FruitBank.Common.Server\bin\Debug\net9.0\AyCode.Utils.dll + ..\..\..\..\FruitBankHybridApp\FruitBank.Common.Server\bin\Debug\net9.0\FruitBank.Common.dll diff --git a/Nop.Plugin.Misc.AIPlugin/Services/EventConsumer.cs b/Nop.Plugin.Misc.AIPlugin/Services/EventConsumer.cs index a09562c..b4cd883 100644 --- a/Nop.Plugin.Misc.AIPlugin/Services/EventConsumer.cs +++ b/Nop.Plugin.Misc.AIPlugin/Services/EventConsumer.cs @@ -1,4 +1,5 @@ using System.Linq; +using FruitBank.Common.Interfaces; using Nop.Core; using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Orders; @@ -96,7 +97,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services System.Diagnostics.Debug.WriteLine($"Spec Attribute: {specificationAttribute.Name}, Option: {specificationAttributeOption.Name}"); // Check if this is your "NeedsToBeMeasured" specification attribute - if (specificationAttribute.Name == "Measureable" && + if (specificationAttribute.Name == "Measureable" && //nameof(MeasuringAttributeValues.IsMeasurable) specificationAttributeOption.Name == "Yes") // or whatever value you set { requiresMeasurement = true; diff --git a/Nop.Plugin.Misc.AIPlugin/Services/FruitBankAttributeService.cs b/Nop.Plugin.Misc.AIPlugin/Services/FruitBankAttributeService.cs new file mode 100644 index 0000000..75410a3 --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Services/FruitBankAttributeService.cs @@ -0,0 +1,122 @@ +#nullable enable +using FruitBank.Common.Interfaces; +using Nop.Core; +using Nop.Core.Domain.Catalog; +using Nop.Core.Domain.Common; +using Nop.Services.Common; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Services; + +public class FruitBankAttributeService(IGenericAttributeService genericAttributeService, IStoreContext storeContext) +{ + public async Task GetGenericAttributeAsync(int entityId, string key, int storeId) + { + return (await genericAttributeService.GetAttributesForEntityAsync(entityId, typeof(TEntity).Name)).SingleOrDefault(ga => ga.StoreId == storeId && ga.Key == key); + } + + public async Task> GetMeasuringAttributesAsync(int entityId, int storeId) + { + var measuringAttributes = (await genericAttributeService.GetAttributesForEntityAsync(entityId, typeof(TEntity).Name)) + .Where(ga => ga.StoreId == storeId && + (ga.Key is nameof(MeasuringAttributeValues.NetWeight) or nameof(MeasuringAttributeValues.GrossWeight) or nameof(MeasuringAttributeValues.IsMeasurable))) + .ToList(); + + return measuringAttributes; + } + + public Task GetMeasuringAttributeValuesAsync(int entityId) + => GetMeasuringAttributeValuesAsync(entityId, storeContext.GetCurrentStore().Id); + + public async Task GetMeasuringAttributeValuesAsync(int entityId, int storeId) + { + var measuringAttributes = await GetMeasuringAttributesAsync(entityId, storeId); + + if (measuringAttributes.Count == 0) return null; + + var measuringAttributeValues = new MeasuringAttributeValues( + CommonHelper.To(measuringAttributes.FirstOrDefault(ga => ga.Key == nameof(MeasuringAttributeValues.NetWeight))), + CommonHelper.To(measuringAttributes.FirstOrDefault(ga => ga.Key == nameof(MeasuringAttributeValues.GrossWeight))), + CommonHelper.To(measuringAttributes.FirstOrDefault(ga => ga.Key == nameof(MeasuringAttributeValues.IsMeasurable)))); + + return measuringAttributeValues; + } + + public Task IsMeasurableEntityAsync(int entityId) => IsMeasurableEntityAsync(entityId, storeContext.GetCurrentStore().Id); + public async Task IsMeasurableEntityAsync(int entityId, int storeId) + { + var measurableAttribute = await GetGenericAttributeAsync(entityId, nameof(MeasuringAttributeValues.IsMeasurable), storeId); + return measurableAttribute != null && CommonHelper.To(measurableAttribute.Value); + } + + public Task InsertOrUpdateMeasuringAttributeValuesAsync(int entityId, MeasuringAttributeValues measuringAttributeValues, bool cumulativeWeightUpdate) + => InsertOrUpdateMeasuringAttributeValuesAsync(entityId, storeContext.GetCurrentStore().Id, measuringAttributeValues, cumulativeWeightUpdate); + + public async Task InsertOrUpdateMeasuringAttributeValuesAsync(int entityId, int storeId, MeasuringAttributeValues measuringAttributeValues, bool cumulativeWeightUpdate) + { + if (!measuringAttributeValues.HasValues()) throw new Exception($"FruitBankAttributeService->InsertOrUpdateMeasuringAttributeValuesAsync; measuringAttributeValues.HasValues() == false; entityId: {entityId}; values: {measuringAttributeValues}"); + + var measuringAttributes = await GetMeasuringAttributesAsync(entityId, storeId); + + var netWeightAttribute = measuringAttributes.FirstOrDefault(ma => ma.Key == nameof(MeasuringAttributeValues.NetWeight)); + if (netWeightAttribute != null) await UpdateMeasuringWeightAttributeValueAsync(netWeightAttribute, measuringAttributeValues.NetWeight!.Value, cumulativeWeightUpdate); + else await InsertGenericAttributeAsync(entityId, nameof(MeasuringAttributeValues.NetWeight), measuringAttributeValues.NetWeight!.Value, storeId); + + var grossWeightAttribute = measuringAttributes.FirstOrDefault(ma => ma.Key == nameof(MeasuringAttributeValues.GrossWeight)); + if (grossWeightAttribute != null) await UpdateMeasuringWeightAttributeValueAsync(grossWeightAttribute, measuringAttributeValues.GrossWeight!.Value, cumulativeWeightUpdate); + else await InsertGenericAttributeAsync(entityId, nameof(MeasuringAttributeValues.GrossWeight), measuringAttributeValues.GrossWeight!.Value, storeId); + + var isMeasurableAttribute = measuringAttributes.FirstOrDefault(ma => ma.Key == nameof(MeasuringAttributeValues.IsMeasurable)); + if (isMeasurableAttribute != null) await UpdateGenericAttributeAsync(isMeasurableAttribute, measuringAttributeValues.IsMeasurable!.Value); + else await InsertGenericAttributeAsync(entityId, nameof(MeasuringAttributeValues.IsMeasurable), measuringAttributeValues.IsMeasurable!.Value, storeId); + } + + private async Task UpdateMeasuringWeightAttributeValueAsync(GenericAttribute genericAttribute, double newWeightValue, bool cumulativeWeightUpdate) + { + await UpdateGenericAttributeAsync(genericAttribute, cumulativeWeightUpdate ? CommonHelper.To(genericAttribute.Value) + newWeightValue : newWeightValue); + } + + public async Task DeleteAllMeasuringAttributesAsync(int entityId, int storeId) + { + var measuringAttributes = await GetMeasuringAttributesAsync(entityId, storeId); + if (measuringAttributes.Count == 0) return; + + foreach (var measuringAttribute in measuringAttributes) + { + await genericAttributeService.DeleteAttributeAsync(measuringAttribute); + } + } + + public async Task InsertGenericAttributeAsync(int entityId, string key, TPropType value, int storeId) + { + var genericAttribute = new GenericAttribute + { + Key = key, + EntityId = entityId, + KeyGroup = typeof(TEntity).Name, + Value = CommonHelper.To(value), + StoreId = storeId + }; + + await genericAttributeService.InsertAttributeAsync(genericAttribute); + } + + public async Task UpdateGenericAttributeAsync(int entityId, string key, TPropType newValue, int storeId) + { + var ga = await GetGenericAttributeAsync(entityId, key, storeId); + await UpdateGenericAttributeAsync(ga!, newValue); + } + + public async Task UpdateGenericAttributeAsync(GenericAttribute genericAttribute, TPropType newValue) + { + genericAttribute.Value = CommonHelper.To(newValue); + await genericAttributeService.UpdateAttributeAsync(genericAttribute); + } + + public async Task DeleteGenericAttributeAsync(int entityId, string key, int storeId) + { + var ga = await GetGenericAttributeAsync(entityId, key, storeId); + if (ga == null) return; + + await genericAttributeService.DeleteAttributeAsync(ga); + } +} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Services/ILockService.cs b/Nop.Plugin.Misc.AIPlugin/Services/ILockService.cs new file mode 100644 index 0000000..160a6b4 --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Services/ILockService.cs @@ -0,0 +1,5 @@ +using Mango.Nop.Services; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Services; + +public interface ILockService : IMgLockService{} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Services/LockService.cs b/Nop.Plugin.Misc.AIPlugin/Services/LockService.cs new file mode 100644 index 0000000..787a38f --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Services/LockService.cs @@ -0,0 +1,14 @@ +using Mango.Nop.Services; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Services; + +public class LockService : MgLockService, ILockService +{ + public LockService() : this(new SemaphoreSlim(1)) + {} + + public LockService(SemaphoreSlim semaphoreSlim) : base(semaphoreSlim) + { + + } +} \ No newline at end of file