#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 Nop.Services.Common; using System.Transactions; using FruitBank.Common.Dtos; using Mango.Nop.Core.Dtos; using Microsoft.CodeAnalysis.CSharp.Syntax; using Nop.Core.Domain.Orders; namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer; public class FruitBankDbContext : MgDbContextBase, IOrderDtoDbSet, IPartnerDbSet, IShippingDbSet, IShippingDocumentDbSet, IShippingItemDbSet, IShippingItemPalletDbSet, IOrderItemPalletDbSet, IShippingDocumentToFilesDbSet, IFilesDbSet { private readonly FruitBankAttributeService _fruitBankAttributeService; private readonly IStoreContext _storeContext; private readonly IProductService _productService; private readonly IStaticCacheManager _staticCacheManager; public OrderDtoDbTable OrderDtos { get; set; } public PartnerDbTable Partners { get; set; } public ShippingDbTable Shippings { get; set; } public ShippingDocumentDbTable ShippingDocuments { get; set; } public ShippingItemDbTable ShippingItems { get; set; } public ShippingItemPalletDbTable ShippingItemPallets { get; set; } public OrderItemPalletDbTable OrderItemPallets { get; set; } public FilesDbTable Files { get; set; } public ShippingDocumentToFilesDbTable ShippingDocumentToFiles { get; set; } public IRepository Products { get; set; } public IRepository Customers { get; set; } public IRepository CustomerRoles { get; set; } public IRepository CustomerRoleMappings { get; set; } public FruitBankDbContext(INopDataProvider dataProvider, ILockService lockService, FruitBankAttributeService fruitBankAttributeService, IStoreContext storeContext, PartnerDbTable partnerDbTable, ShippingDbTable shippingDbTable, ShippingDocumentDbTable shippingDocumentDbTable, ShippingItemDbTable shippingItemDbTable, ShippingItemPalletDbTable shippingItemPalletDbTable, FilesDbTable filesDbTable, ShippingDocumentToFilesDbTable shippingDocumentToFilesDbTable, OrderDtoDbTable orderDtoDbTable, IProductService productService, IStaticCacheManager staticCacheManager, IRepository productRepository, IRepository customerRepository, IRepository customerCustomerRoleMappingRepository, IRepository customerRoleRepository, IEnumerable logWriters) : base(dataProvider, lockService, logWriters) { _storeContext = storeContext; _productService = productService; _staticCacheManager = staticCacheManager; _fruitBankAttributeService = fruitBankAttributeService; Files = filesDbTable; OrderDtos = orderDtoDbTable; Partners = partnerDbTable; Shippings = shippingDbTable; ShippingDocuments = shippingDocumentDbTable; ShippingItems = shippingItemDbTable; ShippingItemPallets = shippingItemPalletDbTable; ShippingDocumentToFiles = shippingDocumentToFilesDbTable; Products = productRepository; Customers = customerRepository; CustomerRoles = customerRoleRepository; CustomerRoleMappings = customerCustomerRoleMappingRepository; } public IQueryable GetCustomersBySystemRoleName(string systemRoleName) { if (systemRoleName.IsNullOrWhiteSpace()) throw new ArgumentException("systemRoleName.IsNullOrWhiteSpace()", nameof(systemRoleName)); var query = from c in Customers.Table join crm in CustomerRoleMappings.Table on c.Id equals crm.CustomerId join cr in CustomerRoles.Table on crm.CustomerRoleId equals cr.Id where c.Active && !c.Deleted && cr.SystemName == systemRoleName select c; 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(bool includeDeleted) => Products.Table.Where(p => includeDeleted || !p.Deleted).OrderBy(o => o.Name); public IQueryable GetAllProductDtos(bool includeDeleted) => GetAllProducts(includeDeleted).Select(product => new ProductDto(product)); public IAsyncEnumerable GetAllMeasuringProductDtos(bool includeDeleted) => GetAllProducts(includeDeleted).SelectAwait(async product => new MeasuringProductDto(product, await GetMeasuringAttributeValuesByProductIdAsync(product.Id))); public async Task GetMeasuringProductDtoByIdAsync(int productId) => await Products.Table.Where(product => product.Id == productId).SelectAwait(async product => new MeasuringProductDto(product, await GetMeasuringAttributeValuesByProductIdAsync(product.Id))).FirstOrDefaultAsync(); public async Task GetMeasuringAttributeValuesByProductIdAsync(int productId) => await _fruitBankAttributeService.GetMeasuringAttributeValuesAsync(productId); public async Task DeleteShippingSafeAsync(Shipping shipping) { await TransactionSafeAsync(async tr => { await Shippings.DeleteAsync(shipping, true); return true; }); } public async Task DeleteShippingDocumentSafeAsync(ShippingDocument shippingDocument) { await TransactionSafeAsync(async tr => { await ShippingDocuments.DeleteAsync(shippingDocument, true); return true; }); } public async Task DeleteShippingItemSafeAsync(ShippingItem shippingItem) { await TransactionSafeAsync(async tr => { await ShippingItems.DeleteAsync(shippingItem, true); return true; }); } public Task UpdateMeasuredShippingItemSafeAsync(ShippingItem shippingItem) { if (shippingItem.IsValidMeasuringValues()) return UpdateShippingItemSafeAsync(shippingItem); Logger.Error("shippingItem.IsMeasurable && !shippingItem.IsValidMeasuringValues()"); return Task.FromResult(false); } public Task UpdateShippingItemSafeAsync(ShippingItem shippingItem) => TransactionSafeAsync(async _ => await UpdateShippingItemAsync(shippingItem)); public async Task UpdateShippingItemAsync(ShippingItem shippingItem) { try { Product? product = null; var productIsMeasurable = false; if (shippingItem.ProductId > 0) { product = await Products.GetByIdAsync(shippingItem.ProductId); if (product == null) throw new Exception($"shippingItem.ProductId > 0 && product == null; shippingItem.ProductId: {shippingItem.ProductId}"); productIsMeasurable = await _fruitBankAttributeService.IsMeasurableEntityAsync(product.Id); } shippingItem.IsMeasurable = productIsMeasurable; //if (shippingItem.ShippingItemPallets is { Count: > 0 }) await AddOrUpdateShippingItemPalletAsync(shippingItem); //await AddOrUpdateShippingItemPalletAsync(shippingItem.ShippingItemPallets.Where(x => x.IsValidMeasuringValues(shippingItem.IsMeasurable)), shippingItem); //Nem tudhatjuk, h minden Pallet-et tartalmaz-e a shippingItem paraméter! A Biztonság kedvéért lekérjük db-ből! - J. shippingItem.ShippingItemPallets = await ShippingItemPallets.GetAllByShippingItemIdAsync(shippingItem.Id, false).ToListAsync(); //Update előtt kivesszük a korábbi ShippingItem-et a db-ből! - J. var dbShippingItem = await ShippingItems.GetByIdAsync(shippingItem.Id, false); if (dbShippingItem == null) throw new Exception($"dbShippingItem == null; shippingItem.Id: {shippingItem.Id}"); var isMeasuredPrerequisite = product != null && shippingItem.PalletsOnDocument == shippingItem.ShippingItemPallets.Count && shippingItem.ShippingItemPallets.All(x => x.IsMeasuredAndValid(shippingItem.IsMeasurable)); SetupShippingItemMeasuringValues(shippingItem, isMeasuredPrerequisite); shippingItem.IsMeasured = isMeasuredPrerequisite && shippingItem.IsValidMeasuringValues(); await ShippingItems.UpdateAsync(shippingItem, shippingItem.IsMeasured != dbShippingItem.IsMeasured); 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) { return true; } var productIdChanged = shippingItem.ProductId != dbShippingItem.ProductId; if (shippingItem.IsMeasured) { product!.StockQuantity += productIdChanged ? shippingItem.MeasuredQuantity : shippingItem.MeasuredQuantity - dbShippingItem.MeasuredQuantity; if (!await UpdateProductStockQuantityAsync(product, true)) throw new Exception($"UpdateProductStockQuantity() == false; shippingItem! product.Id: {product.Id}"); if (productIsMeasurable) await _fruitBankAttributeService.InsertOrUpdateMeasuringAttributeValuesAsync(product.Id, productIdChanged ? shippingItem.MeasuredNetWeight : shippingItem.MeasuredNetWeight - dbShippingItem.MeasuredNetWeight, productIdChanged ? shippingItem.MeasuredGrossWeight : shippingItem.MeasuredGrossWeight - dbShippingItem.MeasuredGrossWeight, shippingItem.IsMeasurable, true); } //if (productIdUnchanged || !dbShippingItem.IsMeasured) return true; if (!productIdChanged && (shippingItem.IsMeasured || !dbShippingItem.IsMeasured)) return true; product = await Products.GetByIdAsync(dbShippingItem.ProductId); if (product != null) { productIsMeasurable = await _fruitBankAttributeService.IsMeasurableEntityAsync(product.Id); product.StockQuantity -= dbShippingItem.MeasuredQuantity; if (!await UpdateProductStockQuantityAsync(product, true)) throw new Exception($"UpdateProductStockQuantity() == false; dbShippingItem! product.Id: {product.Id}"); if (!productIsMeasurable) return true; var measuringValues = new MeasuringAttributeValues(product.Id, -dbShippingItem.MeasuredNetWeight, -dbShippingItem.MeasuredGrossWeight, dbShippingItem.IsMeasurable); await _fruitBankAttributeService.InsertOrUpdateMeasuringAttributeValuesAsync(measuringValues, true); } else Logger.Warning($"product == null; dbShippingItem.ProductId: {dbShippingItem.ProductId}"); //else //TODO: productIdUnchanged-et lekezelni! - J. return true; } catch (Exception ex) { throw new Exception($"UpdateShippingItemAsync error! {shippingItem}; ex: {ex.Message}", ex); } } private static void SetupShippingItemMeasuringValues(ShippingItem shippingItem, bool shippingItemIsMeasured) { shippingItem.MeasuredQuantity = 0; shippingItem.MeasuredNetWeight = 0; shippingItem.MeasuredGrossWeight = 0; if (!shippingItemIsMeasured) return; foreach (var shippingItemPallet in shippingItem.ShippingItemPallets!.Where(x => x.IsMeasured && x.IsValidMeasuringValues(shippingItem.IsMeasurable))) { shippingItem.MeasuredQuantity += shippingItemPallet.TrayQuantity; if (!shippingItem.IsMeasurable) continue; shippingItem.MeasuredNetWeight += shippingItemPallet.NetWeight; shippingItem.MeasuredGrossWeight += shippingItemPallet.GrossWeight; } shippingItem.MeasuredNetWeight = double.Round(shippingItem.MeasuredNetWeight, 1); shippingItem.MeasuredGrossWeight = double.Round(shippingItem.MeasuredGrossWeight, 1); //if (shippingItem.MeasuredQuantity < 0) shippingItem.MeasuredQuantity = 0; //if (!shippingItem.IsMeasurable || shippingItem.MeasuredNetWeight < 0) shippingItem.MeasuredNetWeight = 0; //if (!shippingItem.IsMeasurable || shippingItem.MeasuredGrossWeight < 0) shippingItem.MeasuredGrossWeight = 0; } public async Task AddShippingItemPalletAsync(ShippingItemPallet shippingItemPallet) { if (!await SetupShippingItemPalletMeauringValues(shippingItemPallet)) return null; await ShippingItemPallets.InsertAsync(shippingItemPallet); return shippingItemPallet; } public Task AddShippingItemPalletSafeAsync(ShippingItemPallet shippingItemPallet) { return TransactionSafeAsync(async tr => { try { return (await AddShippingItemPalletAsync(shippingItemPallet)) != null; } catch (Exception ex) { throw new Exception($"AddShippingItemPalletSafeAsync->TransactionSafeAsync error! shippingItemPallet: {shippingItemPallet}; ex: {ex.Message}", ex); } }); } public async Task UpdateShippingItemPalletAsync(ShippingItemPallet shippingItemPallet) { if (!await SetupShippingItemPalletMeauringValues(shippingItemPallet)) return null; await ShippingItemPallets.UpdateAsync(shippingItemPallet); return shippingItemPallet; } public Task UpdateShippingItemPalletSafeAsync(ShippingItemPallet shippingItemPallet) { return TransactionSafeAsync(async tr => { try { return (await UpdateShippingItemPalletAsync(shippingItemPallet)) != null; } catch (Exception ex) { throw new Exception($"UpdateShippingItemPalletSafeAsync->TransactionSafeAsync error! shippingItemPallet: {shippingItemPallet}; ex: {ex.Message}", ex); } }); } public Task AddOrUpdateShippingItemPalletsSafeAsync(ShippingItem shippingItem) => AddOrUpdateShippingItemPalletsSafeAsync(shippingItem.ShippingItemPallets!, shippingItem); public Task AddOrUpdateShippingItemPalletsSafeAsync(IEnumerable shippingItemPallets, ShippingItem parentShippingItem) { return TransactionSafeAsync(async tr => { try { await AddOrUpdateShippingItemPalletAsync(shippingItemPallets, parentShippingItem); return true; } catch (Exception ex) { throw new Exception($"AddOrUpdateShippingItemPalletsSafeAsync->TransactionSafeAsync error! ex: {ex.Message}", ex); } }); } public Task AddOrUpdateShippingItemPalletAsync(ShippingItem shippingItem) => AddOrUpdateShippingItemPalletAsync(shippingItem.ShippingItemPallets!, shippingItem); public async Task AddOrUpdateShippingItemPalletAsync(IEnumerable shippingItemPallets, ShippingItem parentShippingItem) { foreach (var shippingItemPallet in shippingItemPallets) { shippingItemPallet.ShippingItem = parentShippingItem; if (await AddOrUpdateShippingItemPalletAsync(shippingItemPallet) == null) throw new Exception($"AddOrUpdateShippingItemPalletAsync->AddOrUpdateShippingItemPalletAsync() == null"); } } public async Task AddOrUpdateShippingItemPalletSafeAsync(ShippingItemPallet shippingItemPallet) => await TransactionSafeAsync(async tr => await AddOrUpdateShippingItemPalletAsync(shippingItemPallet) != null); public async Task AddOrUpdateShippingItemPalletAsync(ShippingItemPallet shippingItemPallet) { if (shippingItemPallet.Id <= 0) return await AddShippingItemPalletAsync(shippingItemPallet); return await UpdateShippingItemPalletAsync(shippingItemPallet); } public async Task DeleteShippingItemPalletSafeAsync(ShippingItemPallet shippingItemPallet) { await TransactionSafeAsync(async tr => { await ShippingItemPallets.DeleteAsync(shippingItemPallet, false); return true; }); } private async Task SetupShippingItemPalletMeauringValues(ShippingItemPallet shippingItemPallet) { var shippingItem = shippingItemPallet.ShippingItem ?? await ShippingItems.GetByIdAsync(shippingItemPallet.ShippingItemId, false); if (shippingItem == null || shippingItemPallet.ShippingItemId != shippingItem.Id) return false; if (!shippingItem.IsMeasurable) { shippingItemPallet.TareWeight = 0; shippingItemPallet.PalletWeight = 0; shippingItemPallet.GrossWeight = 0; } shippingItemPallet.IsMeasured = shippingItemPallet.IsValidMeasuringValues(shippingItem.IsMeasurable); return true; } private async Task UpdateProductStockQuantityAsync(int productId, bool publishEvent) { var product = await Products.GetByIdAsync(productId); 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, 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, 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}"); //if (updatedRowsCount == 1) return await Task.FromResult(true); //Logger.Error($"Product updatedRowsCount != 1; id: {product.Id}"); //return await Task.FromResult(false); } public async Task> GetShippingDocumentsByShippingIdAsync(int shippingId) { var list = await ShippingDocuments.GetAll(true).Where(sd => sd.ShippingId == shippingId).ToListAsync(); return list; } }