From 070d7ec3d243e2797b4edebbbac25d7cdcd3802a Mon Sep 17 00:00:00 2001 From: Loretta Date: Mon, 1 Dec 2025 16:17:57 +0100 Subject: [PATCH 1/4] .Net10, VS2026; StockTaking in progress... --- .../Controllers/StockSignalREndpointServer.cs | 119 ++++++++++++++++++ .../Controllers/FruitBankDataController.cs | 26 ++-- .../Domains/DataLayer/FruitBankDbContext.cs | 6 +- .../DataLayer/Interfaces/IStockTakingDbSet.cs | 10 ++ .../Interfaces/IStockTakingItemDbSet.cs | 10 ++ .../Interfaces/IStockTakingItemPalletDbSet.cs | 10 ++ .../Domains/DataLayer/StockTakingDbContext.cs | 74 +++++++++++ .../Domains/DataLayer/StockTakingDbTable.cs | 32 +++++ .../DataLayer/StockTakingItemDbTable.cs | 31 +++++ .../DataLayer/StockTakingItemPalletDbTable.cs | 28 +++++ .../Infrastructure/PluginNopStartup.cs | 6 + .../Mapping/NameCompatibility.cs | 6 +- .../Nop.Plugin.Misc.FruitBankPlugin.csproj | 8 +- 13 files changed, 351 insertions(+), 15 deletions(-) create mode 100644 Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs create mode 100644 Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingDbSet.cs create mode 100644 Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingItemDbSet.cs create mode 100644 Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingItemPalletDbSet.cs create mode 100644 Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs create mode 100644 Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbTable.cs create mode 100644 Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemDbTable.cs create mode 100644 Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemPalletDbTable.cs diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs new file mode 100644 index 0000000..2562c71 --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs @@ -0,0 +1,119 @@ +using AyCode.Core.Loggers; +using AyCode.Services.SignalRs; +using FruitBank.Common.Entities; +using FruitBank.Common.Server.Interfaces; +using FruitBank.Common.Server.Services.SignalRs; +using FruitBank.Common.SignalRs; +using Mango.Nop.Core.Loggers; +using Nop.Core; +using Nop.Core.Events; +using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers; + +public class StockSignalREndpointServer(StockTakingDbContext ctx, SignalRSendToClientService sendToClient, IEventPublisher eventPublisher, IWorkContext workContext, IEnumerable logWriters) + : IStockSignalREndpointServer +{ + private const int LastStockTakingDays = 15; + private readonly ILogger _logger = new Logger(logWriters.ToArray()); + + [SignalR(SignalRTags.GetStockTakings)] + public async Task> GetStockTakings() + { + return await ctx.StockTakings.GetAll(true).ToListAsync(); + } + + public async Task> GetStockTakingsByProductId(int productId) + { + throw new NotImplementedException(); + } + + [SignalR(SignalRTags.AddStockTaking)] + public async Task AddStockTaking(StockTaking stockTaking) + { + var result = await ctx.TransactionSafeAsync(async _ => + { + await ctx.StockTakings.InsertAsync(stockTaking); + + var productDtos = await ctx.ProductDtos.GetAll(true).ToListAsync(); + + foreach (var productDto in productDtos) + { + var stockTakingItem = new StockTakingItem + { + StockTakingId = stockTaking.Id, + ProductId = productDto.Id, + //IsMeasurable = productDto.IsMeasurable, + OriginalStockQuantity = productDto.StockQuantity, + OriginalNetWeight = productDto.NetWeight + }; + + await ctx.StockTakingItems.InsertAsync(stockTakingItem); + } + + return true; + }); + + if (result) return await ctx.StockTakings.GetByIdAsync(stockTaking.Id, false); + return null; + + } + + public async Task UpdateStockTaking(StockTaking stockTaking) + { + throw new NotImplementedException(); + } + + [SignalR(SignalRTags.GetStockTakingItems)] + public async Task> GetStockTakingItems() + { + return await ctx.StockTakingItems.GetAll(true).ToListAsync(); + } + + [SignalR(SignalRTags.GetStockTakingItemsById)] + public async Task GetStockTakingItemsById(int stockTakingItemId) + { + var result = await ctx.StockTakingItems.GetByIdAsync(stockTakingItemId, true); + return result; + } + + public async Task> GetStockTakingItemsByProductId(int productId) + { + throw new NotImplementedException(); + } + + public async Task> GetStockTakingItemsByStockTakingId(int stockTakingId) + { + throw new NotImplementedException(); + } + + public async Task AddStockTakingItem(StockTakingItem stockTakingItem) + { + throw new NotImplementedException(); + } + + public async Task UpdateStockTakingItem(StockTakingItem stockTakingItem) + { + throw new NotImplementedException(); + } + + public async Task> GetStockTakingItemPallets() + { + throw new NotImplementedException(); + } + + public async Task> GetStockTakingItemPalletsByProductId(int productId) + { + throw new NotImplementedException(); + } + + public async Task AddStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet) + { + throw new NotImplementedException(); + } + + public async Task UpdateStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs b/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs index c34535c..d80f74f 100644 --- a/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs +++ b/Nop.Plugin.Misc.AIPlugin/Controllers/FruitBankDataController.cs @@ -70,20 +70,30 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers return await ctx.GenericAttributeDtos.GetByIdAsync(genericAttributeDto.Id); } + [SignalR(SignalRTags.GetStockQuantityHistoryDtos)] + public async Task> GetStockQuantityHistoryDtos() + { + _logger.Detail($"GetStockQuantityHistoryDtos invoked; lastDaysCount: {LastShippingDays}"); + + var fromDateUtc = DateTime.UtcNow.Date.AddDays(-LastShippingDays); + return await ctx.StockQuantityHistoryDtos.GetAll(true).Where(sqh => sqh.CreatedOnUtc >= fromDateUtc).ToListAsync(); + } + + [SignalR(SignalRTags.GetStockQuantityHistoryDtosByProductId)] + public async Task> GetStockQuantityHistoryDtosByProductId(int productId) + { + _logger.Detail($"GetStockQuantityHistoryDtosByProductId invoked; productId: {productId}; lastDaysCount: {LastShippingDays}"); + + var fromDateUtc = DateTime.UtcNow.Date.AddDays(-LastShippingDays); + return await ctx.StockQuantityHistoryDtos.GetByProductIdAsync(productId, true).Where(sqh => sqh.CreatedOnUtc >= fromDateUtc).ToListAsync(); + } + [SignalR(SignalRTags.GetMeasuringModels)] public Task> GetMeasuringModels() { throw new NotImplementedException("GetMeasuringModels"); } - [SignalR(SignalRTags.GetStockQuantityHistoryDtos)] - public async Task> GetStockQuantityHistoryDtos() - => await ctx.StockQuantityHistoryDtos.GetAll(true).ToListAsync(); - - [SignalR(SignalRTags.GetStockQuantityHistoryDtosByProductId)] - public async Task> GetStockQuantityHistoryDtosByProductId(int productId) - => await ctx.StockQuantityHistoryDtos.GetByProductIdAsync(productId, true).ToListAsync(); - [SignalR(SignalRTags.GetPartners)] public async Task> GetPartners() { diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs index 1a3587c..8b05e30 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/FruitBankDbContext.cs @@ -6,6 +6,7 @@ using FruitBank.Common.Dtos; using FruitBank.Common.Entities; using FruitBank.Common.Interfaces; using FruitBank.Common.Models; +using Mango.Nop.Core.Dtos; using Mango.Nop.Core.Entities; using Mango.Nop.Core.Extensions; using Mango.Nop.Core.Loggers; @@ -25,6 +26,7 @@ using Nop.Plugin.Misc.FruitBankPlugin.Services; using Nop.Services.Catalog; using Nop.Services.Security; using WebMarkupMin.Core.Loggers; +using static Nop.Services.Security.StandardPermission; namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; @@ -101,8 +103,7 @@ public class FruitBankDbContext : MgDbContextBase, Files = filesDbTable; Partners = partnerDbTable; - Products = productRepository; - + ProductDtos = productDtoDbTable; OrderDtos = orderDtoDbTable; @@ -766,4 +767,5 @@ public class FruitBankDbContext : MgDbContextBase, await CustomerAddressMappings.InsertAsync(customerAddressMapping); return customerAddressMapping; } + } \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingDbSet.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingDbSet.cs new file mode 100644 index 0000000..22f2bff --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingDbSet.cs @@ -0,0 +1,10 @@ +using FruitBank.Common.Entities; +using Mango.Nop.Data.Interfaces; +using Nop.Data; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer.Interfaces; + +public interface IStockTakingDbSet : IMgDbTableBase where TDbTable : IRepository +{ + public TDbTable StockTakings { get; set; } +} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingItemDbSet.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingItemDbSet.cs new file mode 100644 index 0000000..7674bec --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingItemDbSet.cs @@ -0,0 +1,10 @@ +using FruitBank.Common.Entities; +using Mango.Nop.Data.Interfaces; +using Nop.Data; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer.Interfaces; + +public interface IStockTakingItemDbSet : IMgDbTableBase where TDbTable : IRepository +{ + public TDbTable StockTakingItems { get; set; } +} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingItemPalletDbSet.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingItemPalletDbSet.cs new file mode 100644 index 0000000..08eef5e --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/Interfaces/IStockTakingItemPalletDbSet.cs @@ -0,0 +1,10 @@ +using FruitBank.Common.Entities; +using Mango.Nop.Data.Interfaces; +using Nop.Data; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer.Interfaces; + +public interface IStockTakingItemPalletDbSet : IMgDbTableBase where TDbTable : IRepository +{ + public TDbTable StockTakingItemPallets { get; set; } +} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs new file mode 100644 index 0000000..7f77053 --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs @@ -0,0 +1,74 @@ +#nullable enable +using AyCode.Core.Loggers; +using FruitBank.Common.Dtos; +using Mango.Nop.Core.Entities; +using Mango.Nop.Core.Loggers; +using Mango.Nop.Data.Repositories; +using Nop.Core; +using Nop.Core.Caching; +using Nop.Core.Domain.Catalog; +using Nop.Core.Domain.Common; +using Nop.Core.Domain.Orders; +using Nop.Core.Events; +using Nop.Data; +using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer.Interfaces; +using Nop.Plugin.Misc.FruitBankPlugin.Services; +using Nop.Services.Catalog; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; + +public class StockTakingDbContext : MgDbContextBase, + IStockTakingDbSet, + IStockTakingItemDbSet, + IStockTakingItemPalletDbSet +{ + public ProductDtoDbTable ProductDtos { get; set; } + + public StockTakingDbTable StockTakings { get; set; } + public StockTakingItemDbTable StockTakingItems { get; set; } + public StockTakingItemPalletDbTable StockTakingItemPallets { get; set; } + public StockQuantityHistoryDtoDbTable StockQuantityHistoryDtos { get; set; } + + public IRepository GenericAttributes { get; set; } + public IRepository StockQuantityHistories { get; set; } + public IRepository StockQuantityHistoriesExt { get; set; } + + private readonly IStoreContext _storeContext; + private readonly IProductService _productService; + private readonly IStaticCacheManager _staticCacheManager; + protected readonly IEventPublisher _eventPublisher; + + public StockTakingDbContext(INopDataProvider dataProvider, ILockService lockService, IStoreContext storeContext, + ProductDtoDbTable productDtoDbTable, + StockQuantityHistoryDtoDbTable stockQuantityHistoryDtos, + StockTakingDbTable stockTakingDbTable, + StockTakingItemDbTable stockTakingItemDbTable, + StockTakingItemPalletDbTable stockTakingItemPalletDbTable, + IProductService productService, IStaticCacheManager staticCacheManager, + IRepository orderRepository, + IRepository orderItemRepository, + IRepository productRepository, + IRepository genericAttributes, + IRepository stockQuantityHistories, + IRepository stockQuantityHistoriesExt, + IEventPublisher eventPublisher, + IEnumerable logWriters) : base(productRepository, orderRepository, orderItemRepository, dataProvider, lockService, new Logger(logWriters.ToArray())) + { + _eventPublisher = eventPublisher; + _storeContext = storeContext; + _productService = productService; + _staticCacheManager = staticCacheManager; + + ProductDtos = productDtoDbTable; + + GenericAttributes = genericAttributes; + + StockQuantityHistories = stockQuantityHistories; + StockQuantityHistoriesExt = stockQuantityHistoriesExt; + StockQuantityHistoryDtos = stockQuantityHistoryDtos; + + StockTakings = stockTakingDbTable; + StockTakingItems = stockTakingItemDbTable; + StockTakingItemPallets = stockTakingItemPalletDbTable; + } +} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbTable.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbTable.cs new file mode 100644 index 0000000..7f187c7 --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbTable.cs @@ -0,0 +1,32 @@ +using FruitBank.Common.Entities; +using LinqToDB; +using Mango.Nop.Data.Repositories; +using Nop.Core.Caching; +using Nop.Core.Configuration; +using Nop.Core.Events; +using Nop.Data; +using static LinqToDB.Reflection.Methods.LinqToDB.Insert; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; + +public class StockTakingDbTable : MgDbTableBase +{ + public StockTakingDbTable(IEventPublisher eventPublisher, INopDataProvider dataProvider, IShortTermCacheManager shortTermCacheManager, IStaticCacheManager staticCacheManager, AppSettings appSettings) + : base(eventPublisher, dataProvider, shortTermCacheManager, staticCacheManager, appSettings) + { + } + + public override IQueryable GetAll() => base.GetAll(); + + public IQueryable GetAll(bool loadRelations) + { + return loadRelations + ? GetAll() + .LoadWith(st => st.StockTakingItems).ThenLoad(sti => sti.Product).ThenLoad(prod => prod.GenericAttributes) + //.LoadWith(st => st.StockTakingItems).ThenLoad(sti => sti.StockTakingItemPallets) + : GetAll().LoadWith(st => st.StockTakingItems); + } + + public Task GetByIdAsync(int id, bool loadRelations) + => GetAll(loadRelations).FirstOrDefaultAsync(st => st.Id == id); +} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemDbTable.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemDbTable.cs new file mode 100644 index 0000000..324b819 --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemDbTable.cs @@ -0,0 +1,31 @@ +using FruitBank.Common.Entities; +using LinqToDB; +using Mango.Nop.Data.Repositories; +using Nop.Core.Caching; +using Nop.Core.Configuration; +using Nop.Core.Events; +using Nop.Data; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; + +public class StockTakingItemDbTable : MgDbTableBase +{ + public StockTakingItemDbTable(IEventPublisher eventPublisher, INopDataProvider dataProvider, IShortTermCacheManager shortTermCacheManager, IStaticCacheManager staticCacheManager, AppSettings appSettings) + : base(eventPublisher, dataProvider, shortTermCacheManager, staticCacheManager, appSettings) + { + } + + public override IQueryable GetAll() => base.GetAll(); + + public IQueryable GetAll(bool loadRelations) + { + return loadRelations + ? GetAll() + .LoadWith(sti => sti.StockTaking) + //.LoadWith(sti => sti.StockTakingItemPallets) + .LoadWith(sti => sti.Product).ThenLoad(prod => prod.GenericAttributes) + : GetAll(); + } + + public Task GetByIdAsync(int stockTakingItemId, bool loadRelations) => GetAll(loadRelations).FirstOrDefaultAsync(sti => sti.Id == stockTakingItemId); +} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemPalletDbTable.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemPalletDbTable.cs new file mode 100644 index 0000000..3c1c7ff --- /dev/null +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemPalletDbTable.cs @@ -0,0 +1,28 @@ +using FruitBank.Common.Entities; +using LinqToDB; +using Mango.Nop.Data.Repositories; +using Nop.Core.Caching; +using Nop.Core.Configuration; +using Nop.Core.Events; +using Nop.Data; + +namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; + +public class StockTakingItemPalletDbTable : MgDbTableBase +{ + public StockTakingItemPalletDbTable(IEventPublisher eventPublisher, INopDataProvider dataProvider, IShortTermCacheManager shortTermCacheManager, IStaticCacheManager staticCacheManager, AppSettings appSettings) + : base(eventPublisher, dataProvider, shortTermCacheManager, staticCacheManager, appSettings) + { + } + + public override IQueryable GetAll() => base.GetAll(); + + public IQueryable GetAll(bool loadRelations) + { + return loadRelations + ? GetAll() + .LoadWith(stip => stip.StockTakingItem).ThenLoad(sti => sti.StockTaking) + .LoadWith(stip => stip.StockTakingItem).ThenLoad(sti => sti.Product).ThenLoad(prod => prod.GenericAttributes) + : GetAll(); + } +} \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs b/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs index e1f11a7..9f836f3 100644 --- a/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs +++ b/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs @@ -75,11 +75,17 @@ public class PluginNopStartup : INopStartup services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); //services.AddScoped(); services.AddScoped(); diff --git a/Nop.Plugin.Misc.AIPlugin/Mapping/NameCompatibility.cs b/Nop.Plugin.Misc.AIPlugin/Mapping/NameCompatibility.cs index 010dd47..e4d2e6f 100644 --- a/Nop.Plugin.Misc.AIPlugin/Mapping/NameCompatibility.cs +++ b/Nop.Plugin.Misc.AIPlugin/Mapping/NameCompatibility.cs @@ -7,6 +7,7 @@ using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Common; using Nop.Core.Domain.Orders; using Nop.Data.Mapping; +using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; namespace Nop.Plugin.Misc.FruitBankPlugin.Mapping; @@ -37,7 +38,10 @@ public partial class NameCompatibility : INameCompatibility { typeof(StockQuantityHistoryDto), nameof(StockQuantityHistory)}, { typeof(StockQuantityHistoryExt), FruitBankConstClient.StockQuantityHistoryExtDbTableName}, - + + { typeof(StockTaking), FruitBankConstClient.StockTakingDbTableName}, + { typeof(StockTakingItem), FruitBankConstClient.StockTakingItemDbTableName}, + { typeof(StockTakingItemPallet), FruitBankConstClient.StockTakingItemPalletDbTableName}, }; diff --git a/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj b/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj index 2e1a406..8cb8ff4 100644 --- a/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj +++ b/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj @@ -24,10 +24,10 @@ - - - - + + + + From bb553ed35d78bb0fafe3359c36d1da0f39f4f4bb Mon Sep 17 00:00:00 2001 From: Loretta Date: Thu, 4 Dec 2025 13:52:46 +0100 Subject: [PATCH 2/4] StockTaking in progress... --- .../Controllers/StockSignalREndpointServer.cs | 39 ++++++++++---- .../Domains/DataLayer/OrderDtoDbTable.cs | 8 ++- .../Domains/DataLayer/OrderItemDtoDbTable.cs | 4 ++ .../Domains/DataLayer/StockTakingDbContext.cs | 54 ++++++++++++++++++- .../Domains/DataLayer/StockTakingDbTable.cs | 2 +- .../DataLayer/StockTakingItemDbTable.cs | 9 +++- 6 files changed, 102 insertions(+), 14 deletions(-) diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs index 2562c71..82ada7e 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs @@ -1,11 +1,14 @@ using AyCode.Core.Loggers; using AyCode.Services.SignalRs; +using DevExpress.Data.Helpers; using FruitBank.Common.Entities; +using FruitBank.Common.Enums; using FruitBank.Common.Server.Interfaces; using FruitBank.Common.Server.Services.SignalRs; using FruitBank.Common.SignalRs; using Mango.Nop.Core.Loggers; using Nop.Core; +using Nop.Core.Domain.Orders; using Nop.Core.Events; using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; @@ -18,9 +21,9 @@ public class StockSignalREndpointServer(StockTakingDbContext ctx, SignalRSendToC private readonly ILogger _logger = new Logger(logWriters.ToArray()); [SignalR(SignalRTags.GetStockTakings)] - public async Task> GetStockTakings() + public async Task> GetStockTakings(bool loadRelations) { - return await ctx.StockTakings.GetAll(true).ToListAsync(); + return await ctx.StockTakings.GetAll(loadRelations).ToListAsync(); } public async Task> GetStockTakingsByProductId(int productId) @@ -37,15 +40,21 @@ public class StockSignalREndpointServer(StockTakingDbContext ctx, SignalRSendToC var productDtos = await ctx.ProductDtos.GetAll(true).ToListAsync(); + var orderItemDtos = (await ctx.OrderItemDtos.GetAllByProductIds(productDtos.Select(p => p.Id)) + .Where(oi => oi.OrderDto.OrderStatusId != (int)OrderStatus.Complete).ToArrayAsync()) + .Where(x => x.MeasuringStatus == MeasuringStatus.NotStarted).ToLookup(k => k.ProductId, v => v); + foreach (var productDto in productDtos) { var stockTakingItem = new StockTakingItem { StockTakingId = stockTaking.Id, ProductId = productDto.Id, - //IsMeasurable = productDto.IsMeasurable, + IsMeasurable = productDto.IsMeasurable, OriginalStockQuantity = productDto.StockQuantity, - OriginalNetWeight = productDto.NetWeight + InProcessOrdersQuantity = orderItemDtos[productDto.Id].Sum(x => x.Quantity), + //A NetWeight-et nem növeljük meg, mert az nem vonódik le automatikusan a rendelés létrehozásakor! - J. + OriginalNetWeight = productDto.NetWeight //double.Round(productDto.NetWeight + orderItemDtos[productDto.Id].Sum(x => x.NetWeight), 1) }; await ctx.StockTakingItems.InsertAsync(stockTakingItem); @@ -59,9 +68,13 @@ public class StockSignalREndpointServer(StockTakingDbContext ctx, SignalRSendToC } + [SignalR(SignalRTags.UpdateStockTaking)] public async Task UpdateStockTaking(StockTaking stockTaking) { - throw new NotImplementedException(); + if(stockTaking == null) return null; + + await ctx.StockTakings.UpdateAsync(stockTaking); + return await ctx.StockTakings.GetByIdAsync(stockTaking.Id, true); } [SignalR(SignalRTags.GetStockTakingItems)] @@ -77,14 +90,16 @@ public class StockSignalREndpointServer(StockTakingDbContext ctx, SignalRSendToC return result; } + [SignalR(SignalRTags.GetStockTakingItemsByProductId)] public async Task> GetStockTakingItemsByProductId(int productId) { - throw new NotImplementedException(); + return await ctx.StockTakingItems.GetAllByProductId(productId, true).ToListAsync(); } + [SignalR(SignalRTags.GetStockTakingItemsByStockTakingId)] public async Task> GetStockTakingItemsByStockTakingId(int stockTakingId) { - throw new NotImplementedException(); + return await ctx.StockTakingItems.GetAllByStockTakingId(stockTakingId, true).ToListAsync(); } public async Task AddStockTakingItem(StockTakingItem stockTakingItem) @@ -109,11 +124,17 @@ public class StockSignalREndpointServer(StockTakingDbContext ctx, SignalRSendToC public async Task AddStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet) { - throw new NotImplementedException(); + return await ctx.AddStockTakingItemPallet(stockTakingItemPallet); } public async Task UpdateStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet) { - throw new NotImplementedException(); + return await ctx.UpdateStockTakingItemPallet(stockTakingItemPallet); + } + + [SignalR(SignalRTags.AddOrUpdateMeasuredStockTakingItemPallet)] + public async Task AddOrUpdateMeasuredStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet) + { + return await ctx.AddOrUpdateMeasuredStockTakingItemPallet(stockTakingItemPallet); } } \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderDtoDbTable.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderDtoDbTable.cs index 3e19d00..c4583e0 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderDtoDbTable.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderDtoDbTable.cs @@ -1,14 +1,15 @@ using FruitBank.Common.Dtos; using FruitBank.Common.Entities; using LinqToDB; +using Mango.Nop.Core.Loggers; using Mango.Nop.Data.Repositories; using Nop.Core.Caching; using Nop.Core.Configuration; using Nop.Core.Domain.Orders; +using Nop.Core.Domain.Payments; using Nop.Core.Events; using Nop.Data; -using Mango.Nop.Core.Loggers; -using Nop.Core.Domain.Payments; +using System.Linq; namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; @@ -47,5 +48,8 @@ public class OrderDtoDbTable : MgDtoDbTableBase public IQueryable GetAllByProductId(int productId, bool loadRelations = true) => GetAll(loadRelations).Where(o => o.OrderItemDtos.Any(oi => oi.ProductId == productId)); + public IQueryable GetAllByProductIds(IEnumerable productIds, bool loadRelations = true) + => GetAll(loadRelations).Where(o => o.OrderItemDtos.Any(oi => productIds.Contains(oi.ProductId))); + public IQueryable GetAllByIds(IEnumerable orderIds, bool loadRelations = true) => GetAll(loadRelations).Where(o => orderIds.Contains(o.Id)); } diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderItemDtoDbTable.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderItemDtoDbTable.cs index 55d8eb9..dca5e88 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderItemDtoDbTable.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderItemDtoDbTable.cs @@ -31,8 +31,12 @@ public class OrderItemDtoDbTable : MgDtoDbTableBase public Task GetByIdAsync(int orderItemId, bool loadRelations) => GetAll(loadRelations).Where(oi => oi.Id == orderItemId).FirstOrDefaultAsync(null); public IQueryable GetAllByOrderId(int orderId, bool loadRelations = true) => GetAll(loadRelations).Where(oi => oi.OrderId == orderId); + public IQueryable GetAllByProductId(int productId, bool loadRelations = true) => GetAll(loadRelations).Where(oi => oi.ProductId == productId); + public IQueryable GetAllByProductIds(IEnumerable productIds, bool loadRelations = true) + => GetAll(loadRelations).Where(oi => productIds.Contains(oi.ProductId)); + public IQueryable GetAllByIds(IEnumerable orderItemIds, bool loadRelations = true) => GetAll(loadRelations).Where(oi => orderItemIds.Contains(oi.Id)); public IQueryable GetAllByOrderIds(IEnumerable orderIds, bool loadRelations = true) => GetAll(loadRelations).Where(oi => orderIds.Contains(oi.OrderId)); } \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs index 7f77053..7cf2de4 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs @@ -1,6 +1,8 @@ #nullable enable +using System.Threading.Tasks; using AyCode.Core.Loggers; using FruitBank.Common.Dtos; +using FruitBank.Common.Entities; using Mango.Nop.Core.Entities; using Mango.Nop.Core.Loggers; using Mango.Nop.Data.Repositories; @@ -17,12 +19,14 @@ using Nop.Services.Catalog; namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; -public class StockTakingDbContext : MgDbContextBase, +public class StockTakingDbContext : MgDbContextBase, IStockTakingDbSet, + IOrderItemDtoDbSet, IStockTakingItemDbSet, IStockTakingItemPalletDbSet { public ProductDtoDbTable ProductDtos { get; set; } + public OrderItemDtoDbTable OrderItemDtos { get; set; } public StockTakingDbTable StockTakings { get; set; } public StockTakingItemDbTable StockTakingItems { get; set; } @@ -40,6 +44,7 @@ public class StockTakingDbContext : MgDbContextBase, public StockTakingDbContext(INopDataProvider dataProvider, ILockService lockService, IStoreContext storeContext, ProductDtoDbTable productDtoDbTable, + OrderItemDtoDbTable orderItemDtoDbTable, StockQuantityHistoryDtoDbTable stockQuantityHistoryDtos, StockTakingDbTable stockTakingDbTable, StockTakingItemDbTable stockTakingItemDbTable, @@ -60,6 +65,7 @@ public class StockTakingDbContext : MgDbContextBase, _staticCacheManager = staticCacheManager; ProductDtos = productDtoDbTable; + OrderItemDtos = orderItemDtoDbTable; GenericAttributes = genericAttributes; @@ -71,4 +77,50 @@ public class StockTakingDbContext : MgDbContextBase, StockTakingItems = stockTakingItemDbTable; StockTakingItemPallets = stockTakingItemPalletDbTable; } + + public async Task AddOrUpdateMeasuredStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet) + { + if (stockTakingItemPallet.Id == 0) return await AddStockTakingItemPallet(stockTakingItemPallet); + return await UpdateStockTakingItemPallet(stockTakingItemPallet); + } + + public async Task AddStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet) + { + await TransactionSafeAsync(async _ => + { + await StockTakingItemPallets.InsertAsync(stockTakingItemPallet); + await RefreshStockTakingItemMeasuredValuesFromPallets(stockTakingItemPallet.StockTakingItemId); + + return true; + }); + + return stockTakingItemPallet; + } + + public async Task UpdateStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet) + { + await TransactionSafeAsync(async _ => + { + await StockTakingItemPallets.UpdateAsync(stockTakingItemPallet); + await RefreshStockTakingItemMeasuredValuesFromPallets(stockTakingItemPallet.StockTakingItemId); + + return true; + }); + + return stockTakingItemPallet; + } + + private async Task RefreshStockTakingItemMeasuredValuesFromPallets(int stockTakingItemId) + { + var stockTakingItem = await StockTakingItems.GetByIdAsync(stockTakingItemId, true)!; + + if (stockTakingItem.StockTaking!.IsClosed) throw new Exception($"stockTakingItem.StockTaking!.IsClosed"); + + stockTakingItem.IsMeasured = stockTakingItem.StockTakingItemPallets!.Count > 0; + stockTakingItem.MeasuredStockQuantity = stockTakingItem.StockTakingItemPallets.Sum(x => x.TrayQuantity); + + if (stockTakingItem.IsMeasurable) stockTakingItem.MeasuredNetWeight = double.Round(stockTakingItem.StockTakingItemPallets.Sum(x => x.NetWeight), 1); + + await StockTakingItems.UpdateAsync(stockTakingItem); + } } \ No newline at end of file diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbTable.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbTable.cs index 7f187c7..be44211 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbTable.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbTable.cs @@ -24,7 +24,7 @@ public class StockTakingDbTable : MgDbTableBase ? GetAll() .LoadWith(st => st.StockTakingItems).ThenLoad(sti => sti.Product).ThenLoad(prod => prod.GenericAttributes) //.LoadWith(st => st.StockTakingItems).ThenLoad(sti => sti.StockTakingItemPallets) - : GetAll().LoadWith(st => st.StockTakingItems); + : GetAll();//.LoadWith(st => st.StockTakingItems); } public Task GetByIdAsync(int id, bool loadRelations) diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemDbTable.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemDbTable.cs index 324b819..65e98b2 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemDbTable.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingItemDbTable.cs @@ -22,10 +22,17 @@ public class StockTakingItemDbTable : MgDbTableBase return loadRelations ? GetAll() .LoadWith(sti => sti.StockTaking) - //.LoadWith(sti => sti.StockTakingItemPallets) + .LoadWith(sti => sti.StockTakingItemPallets) .LoadWith(sti => sti.Product).ThenLoad(prod => prod.GenericAttributes) : GetAll(); } public Task GetByIdAsync(int stockTakingItemId, bool loadRelations) => GetAll(loadRelations).FirstOrDefaultAsync(sti => sti.Id == stockTakingItemId); + + public IQueryable GetAllByProductId(int productId, bool loadRelations) + => GetAll(loadRelations).Where(x => x.ProductId == productId); + + public IQueryable GetAllByStockTakingId(int stockTakingId, bool loadRelations) + => GetAll(loadRelations).Where(x => x.StockTakingId == stockTakingId); + } \ No newline at end of file From e178c18f80d93d238ff0792df5cf5893cee8ba43 Mon Sep 17 00:00:00 2001 From: Loretta Date: Mon, 8 Dec 2025 15:49:51 +0100 Subject: [PATCH 3/4] Add stock-taking enhancements and validation updates Enhanced stock-taking functionality by introducing the `CloseStockTaking` method in `StockTakingDbContext` to manage session closures with validation. Added the `IsReadyForClose` method to `IMgStockTaking` and its implementation in `MgStockTaking`. Integrated `FruitBankDbContext` for stock updates. Improved logging in `StockSignalREndpointServer` and added a new SignalR endpoint for closing stock-taking sessions. Updated `AddStockTaking` to initialize properties for new entries. Simplified loading logic in `OrderItemDtoDbTable` by commenting out unnecessary `.ThenLoad` chains. Enhanced validation in `RefreshStockTakingItemMeasuredValuesFromPallets` and adjusted return statements in `AddOrUpdateMeasuredStockTakingItemPallet` and `UpdateStockTakingItemPallet` to fetch updated entities. These changes improve maintainability, robustness, and functionality across the codebase. --- .../Controllers/StockSignalREndpointServer.cs | 17 ++++++++ .../Domains/DataLayer/OrderItemDtoDbTable.cs | 2 +- .../Domains/DataLayer/StockTakingDbContext.cs | 39 ++++++++++++++++--- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs index 82ada7e..4f7040c 100644 --- a/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs +++ b/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Controllers/StockSignalREndpointServer.cs @@ -23,6 +23,7 @@ public class StockSignalREndpointServer(StockTakingDbContext ctx, SignalRSendToC [SignalR(SignalRTags.GetStockTakings)] public async Task> GetStockTakings(bool loadRelations) { + _logger.Debug($"GetStockTakings invoke. loadRelations: {loadRelations}"); return await ctx.StockTakings.GetAll(loadRelations).ToListAsync(); } @@ -31,11 +32,27 @@ public class StockSignalREndpointServer(StockTakingDbContext ctx, SignalRSendToC throw new NotImplementedException(); } + [SignalR(SignalRTags.CloseStockTaking)] + public async Task CloseStockTaking(int stockTakingId) + { + var result = await ctx.TransactionSafeAsync(async _ => + { + await ctx.CloseStockTaking(stockTakingId); + return true; + }); + + if (result) return await ctx.StockTakings.GetByIdAsync(stockTakingId, false); + return null; + } + [SignalR(SignalRTags.AddStockTaking)] public async Task AddStockTaking(StockTaking stockTaking) { var result = await ctx.TransactionSafeAsync(async _ => { + stockTaking.IsClosed = false; + stockTaking.StartDateTime = DateTime.Now; + await ctx.StockTakings.InsertAsync(stockTaking); var productDtos = await ctx.ProductDtos.GetAll(true).ToListAsync(); diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderItemDtoDbTable.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderItemDtoDbTable.cs index dca5e88..1ea4d4c 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderItemDtoDbTable.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/OrderItemDtoDbTable.cs @@ -24,7 +24,7 @@ public class OrderItemDtoDbTable : MgDtoDbTableBase .LoadWith(oi => oi.OrderDto).ThenLoad(o => o.Customer) .LoadWith(oi => oi.OrderDto).ThenLoad(o => o.OrderNotes) .LoadWith(oi => oi.OrderDto).ThenLoad(o => o.GenericAttributes) - .LoadWith(oi => oi.OrderItemPallets).ThenLoad(oip => oip.OrderItemDto).ThenLoad(oi => oi.GenericAttributes) + .LoadWith(oi => oi.OrderItemPallets)//.ThenLoad(oip => oip.OrderItemDto).ThenLoad(oi => oi.GenericAttributes) .LoadWith(oi => oi.ProductDto).ThenLoad(prod => prod.GenericAttributes); } diff --git a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs index 7cf2de4..a57d217 100644 --- a/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs +++ b/Nop.Plugin.Misc.AIPlugin/Domains/DataLayer/StockTakingDbContext.cs @@ -25,6 +25,7 @@ public class StockTakingDbContext : MgDbContextBase, IStockTakingItemDbSet, IStockTakingItemPalletDbSet { + private FruitBankDbContext _fruitBankDbContext; public ProductDtoDbTable ProductDtos { get; set; } public OrderItemDtoDbTable OrderItemDtos { get; set; } @@ -42,7 +43,7 @@ public class StockTakingDbContext : MgDbContextBase, private readonly IStaticCacheManager _staticCacheManager; protected readonly IEventPublisher _eventPublisher; - public StockTakingDbContext(INopDataProvider dataProvider, ILockService lockService, IStoreContext storeContext, + public StockTakingDbContext(INopDataProvider dataProvider, ILockService lockService, IStoreContext storeContext, FruitBankDbContext fruitBankDbContext, ProductDtoDbTable productDtoDbTable, OrderItemDtoDbTable orderItemDtoDbTable, StockQuantityHistoryDtoDbTable stockQuantityHistoryDtos, @@ -64,6 +65,8 @@ public class StockTakingDbContext : MgDbContextBase, _productService = productService; _staticCacheManager = staticCacheManager; + _fruitBankDbContext = fruitBankDbContext; + ProductDtos = productDtoDbTable; OrderItemDtos = orderItemDtoDbTable; @@ -78,6 +81,28 @@ public class StockTakingDbContext : MgDbContextBase, StockTakingItemPallets = stockTakingItemPalletDbTable; } + public async Task CloseStockTaking(int stockTakingId) + { + var stockTaking = await StockTakings.GetByIdAsync(stockTakingId, true); + + if (!stockTaking.IsReadyForClose()) throw new Exception($"Not all IsRequiredForMeasuring items are IsMeasured! IsReadyForClose: false;"); + + var count = 0; + foreach (var stockTakingItem in stockTaking.StockTakingItems!.Where(stockTakingItem => stockTakingItem is { IsMeasured: true, IsInvalid: false })) + { + count++; + + //await _fruitBankDbContext.UpdateStockQuantityAndWeightAsync(stockTakingItem.Product!, stockTakingItem.QuantityDiff, + // $"Leltár által módosítva! stockTakingId: #{stockTaking.Id}, stockTakingItemId: #{stockTakingItem.Id}", + // stockTakingItem.NetWeightDiff); + } + + stockTaking.IsClosed = true; + await StockTakings.UpdateAsync(stockTaking); + + Logger.Info($"StockTaking closed! stockTakingId: {stockTaking.Id}; stockTakingItems count: {count}"); + } + public async Task AddOrUpdateMeasuredStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet) { if (stockTakingItemPallet.Id == 0) return await AddStockTakingItemPallet(stockTakingItemPallet); @@ -94,7 +119,7 @@ public class StockTakingDbContext : MgDbContextBase, return true; }); - return stockTakingItemPallet; + return await StockTakingItemPallets.GetByIdAsync(stockTakingItemPallet.Id); } public async Task UpdateStockTakingItemPallet(StockTakingItemPallet stockTakingItemPallet) @@ -107,16 +132,20 @@ public class StockTakingDbContext : MgDbContextBase, return true; }); - return stockTakingItemPallet; + return await StockTakingItemPallets.GetByIdAsync(stockTakingItemPallet.Id); } private async Task RefreshStockTakingItemMeasuredValuesFromPallets(int stockTakingItemId) { var stockTakingItem = await StockTakingItems.GetByIdAsync(stockTakingItemId, true)!; - if (stockTakingItem.StockTaking!.IsClosed) throw new Exception($"stockTakingItem.StockTaking!.IsClosed"); + if (stockTakingItem.IsInvalid) throw new Exception($"stockTakingItem.IsInvalid"); + if (stockTakingItem.StockTaking!.IsClosed) throw new Exception($"stockTakingItem.StockTaking.IsClosed"); + if (stockTakingItem.StockTakingItemPallets!.Count == 0) throw new Exception($"stockTakingItem.StockTakingItemPallets.Count == 0"); + if (stockTakingItem.StockTakingItemPallets!.Any(x => !x.IsValidMeasuringValues(stockTakingItem.IsMeasurable))) throw new Exception($"IsValidMeasuringValues == false"); - stockTakingItem.IsMeasured = stockTakingItem.StockTakingItemPallets!.Count > 0; + + stockTakingItem.IsMeasured = true; stockTakingItem.MeasuredStockQuantity = stockTakingItem.StockTakingItemPallets.Sum(x => x.TrayQuantity); if (stockTakingItem.IsMeasurable) stockTakingItem.MeasuredNetWeight = double.Round(stockTakingItem.StockTakingItemPallets.Sum(x => x.NetWeight), 1); From a64089f6a899317bb020b16d88618973bd85ffcb Mon Sep 17 00:00:00 2001 From: Loretta Date: Thu, 11 Dec 2025 23:46:36 +0100 Subject: [PATCH 4/4] Minimal SignalR test hub and endpoint for isolated testing Refactored Mango.Sandbox.EndPoints to enable minimal, dependency-light SignalR endpoint testing. Introduced DevAdminSignalRHubSandbox and TestSignalREndpoint for protocol/contract tests without full NopCommerce/FruitBank infra. Added SignalRClientSandbox and comprehensive MSTest coverage for all parameter types. Simplified Program.cs startup, updated project references, and added minimal logger. Original SignalREndpointTests replaced with focused, low-level and high-level tests. CORS and DTOs updated for compatibility. --- Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs | 1 + Nop.Plugin.Misc.MangoCore/Infrastructure/PluginNopStartup.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs b/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs index 9f836f3..e997eb6 100644 --- a/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs +++ b/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs @@ -169,6 +169,7 @@ public class PluginNopStartup : INopStartup { endpoints.MapHub(loggrHubEndPoint, options => { + options.Transports = HttpTransportType.WebSockets; options.AllowStatefulReconnects = false; }); }); diff --git a/Nop.Plugin.Misc.MangoCore/Infrastructure/PluginNopStartup.cs b/Nop.Plugin.Misc.MangoCore/Infrastructure/PluginNopStartup.cs index 25f66ba..e885e40 100644 --- a/Nop.Plugin.Misc.MangoCore/Infrastructure/PluginNopStartup.cs +++ b/Nop.Plugin.Misc.MangoCore/Infrastructure/PluginNopStartup.cs @@ -24,7 +24,7 @@ public class PluginNopStartup : INopStartup feature.AddPolicy( "AllowBlazorClient", apiPolicy => apiPolicy - .WithOrigins(["https://localhost:7144", "https://measurementtest.fruitbank.hu", "https://localhost:60589", "http://localhost:5000"]) + .WithOrigins("https://localhost:7144", "https://measurementtest.fruitbank.hu", "https://localhost:60589", "http://localhost:5000", "https://localhost:59579") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials()