using EgwCoreLib.Lux.Core.RestPayload; using EgwCoreLib.Lux.Data.DbModel.Items; using Microsoft.EntityFrameworkCore; using System.Globalization; using static EgwCoreLib.Lux.Core.Enums; namespace EgwCoreLib.Lux.Data.Repository.Items { public class ItemRepository : BaseRepository, IItemRepository { #region Public Constructors public ItemRepository(IDbContextFactory ctxFactory) : base(ctxFactory) { } #endregion Public Constructors #region Public Methods public async Task AddAsync(ItemModel entity) { await using var dbCtx = await CreateContextAsync(); await dbCtx.DbSetItem.AddAsync(entity); return await dbCtx.SaveChangesAsync() > 0; } public async Task DeleteAsync(ItemModel entity) { await using var dbCtx = await CreateContextAsync(); dbCtx.DbSetItem.Remove(entity); return await dbCtx.SaveChangesAsync() > 0; } public async Task> GetAltAsync(int recId) { await using var dbCtx = await CreateContextAsync(); List dbResult = new List(); // cerco singolo record x partire... var currRec = dbCtx .DbSetItem .Where(x => x.ItemID == recId) .FirstOrDefault(); if ((currRec != null)) { // se è un record che ha parentId > 0 --> cerco da quello record analoghi + parent if (currRec.ItemIDParent > 0) { dbResult = await dbCtx .DbSetItem .Where(x => x.ItemID == currRec.ItemIDParent || x.ItemIDParent == currRec.ItemIDParent) .ToListAsync(); } // altrimenti cerco child collegati else { dbResult = await dbCtx .DbSetItem .Where(x => x.ItemID == currRec.ItemID || x.ItemIDParent == currRec.ItemID) .ToListAsync(); } } return dbResult; } public async Task GetByIdAsync(int recId) { await using var dbCtx = await CreateContextAsync(); return await dbCtx.DbSetItem .Where(x => x.ItemID == recId) .FirstOrDefaultAsync(); } public async Task> GetFiltAsync(string CodGroup, ItemClassType ItemType) { await using var dbCtx = await CreateContextAsync(); return await dbCtx.DbSetItem .Where(x => (string.IsNullOrEmpty(CodGroup) || x.CodGroup == CodGroup) && (ItemType == ItemClassType.ND || x.ItemType == ItemType)) .AsNoTracking() .Include(g => g.ItemGroupNav) .ToListAsync(); } public async Task> GetSearchAsync(string term) { await using var dbCtx = await CreateContextAsync(); return await dbCtx.DbSetItem .Where(x => x.Description.Contains(term, StringComparison.InvariantCultureIgnoreCase) || x.ExtItemCode.Contains(term, StringComparison.InvariantCultureIgnoreCase) || x.SupplCode.Contains(term, StringComparison.InvariantCultureIgnoreCase)) .AsNoTracking() //.Include(g => g.ItemGroupNav) .ToListAsync(); } public async Task MassUpdateAsync(List list2upd, double setCost, double defMargin, double defQtyMax, string defUM, int roundVal = 0, double scaleFactor = 1_000_000.0) { bool answ = false; if (list2upd == null || !list2upd.Any()) return answ; await using var dbCtx = await CreateContextAsync(); // Validate input if (setCost <= 0) throw new ArgumentException("setCost must be greater than 0."); // Step 1: Extract width and height from ExtItemCode var itemUpdates = new List(); foreach (var item in list2upd) { if (string.IsNullOrWhiteSpace(item.ItemCode)) continue; // Try to parse ExtItemCode: "Pine-200.0x360.0" if (!item.ItemCode.Contains("-") || !item.ItemCode.Contains("x")) { // Skip invalid format continue; } // Split by "-" to get prefix and number part var parts = item.ItemCode.Split('-', 2); if (parts.Length < 2) { continue; } string numberPart = parts[1]; // e.g. "200.0x360.0" // Split by "x" to get width and height var widthHeight = numberPart.Split('x', 2); if (widthHeight.Length < 2) { continue; } if (!double.TryParse(widthHeight[0], NumberStyles.Any, CultureInfo.InvariantCulture, out double width) || !double.TryParse(widthHeight[1], NumberStyles.Any, CultureInfo.InvariantCulture, out double height)) { continue; } // Step 2: Calculate Cost using formula: // Cost = setCost / 1,000,000 * width * height double calculatedCost = (setCost / scaleFactor) * width * height; // if requested do round ceiling if (roundVal > 0) { calculatedCost = Math.Ceiling(calculatedCost / roundVal) * roundVal; } // Optional: you can also apply margin to cost if needed, but you said "Cost = ..." // So we're just computing it based on width/height // Step 4: Create a new ItemModel with updated values var updatedItem = new ItemModel { ItemID = item.ItemID, ExtItemCode = item.ItemCode, // keep original Cost = calculatedCost, Margin = defMargin, QtyMax = defQtyMax, UM = defUM }; itemUpdates.Add(updatedItem); } // Step 5: Update database using EF Core (EF Core doesn't support "update" on entire list directly) // We'll use .UpdateRange() or a raw update via .Where() and .SetProperty() // ✅ Use EF Core's Update method (for bulk update) if (itemUpdates.Any()) { // Update only the ones that exist in the DB var existingItems = await dbCtx.DbSetItem .Where(i => itemUpdates.Select(ui => ui.ItemID).Contains(i.ItemID)) .ToListAsync(); if (existingItems.Any()) { // Update existing records using EF Core's Update method foreach (var updatedItem in itemUpdates) { var existing = existingItems.FirstOrDefault(i => i.ItemID == updatedItem.ItemID); if (existing != null) { // Update only the fields we're setting existing.Cost = updatedItem.Cost; existing.Margin = updatedItem.Margin; existing.QtyMax = updatedItem.QtyMax; } } answ = await dbCtx.SaveChangesAsync() > 0; } } return answ; } public async Task UpdateAsync(ItemModel entity) { await using var dbCtx = await CreateContextAsync(); // Recuperiamo l'entità tracciata dal context var trackedEntity = await dbCtx.DbSetItem.FirstOrDefaultAsync(x => x.ItemID == entity.ItemID); if (trackedEntity != null) { // Aggiorna i valori dell'entità tracciata con quelli della nuova dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity); } else { dbCtx.DbSetItem.Update(entity); } return await dbCtx.SaveChangesAsync() > 0; } public async Task UpsertFromBomAsync(List bomList) { await using var dbCtx = await CreateContextAsync(); // Spostato in ItemGroupRepository.AddMissingAsync #if false // in primis calcolo i distinct dei CodGroup x eventuale insert preventivo List distCodGroups = bomList .Select(i => i.ClassCode) .Distinct() .Where(c => !string.IsNullOrWhiteSpace(c)) .ToList(); // recupero l'elenco degli itemGroup gestiti var itemGroupList = await dbCtx .DbSetItemGroup .ToListAsync(); // elenco da inserire... var codGroupsToInsert = distCodGroups .Where(x => !itemGroupList.Any(i => i.CodGroup == x)) .Select(x => new ItemGroupModel() { CodGroup = x, Description = x }) .ToList(); // se ci sono inserisco! if (codGroupsToInsert != null && codGroupsToInsert.Count > 0) { dbCtx .DbSetItemGroup .AddRange(codGroupsToInsert); // salvo... await dbCtx.SaveChangesAsync(); } #endif // prendo solo elementi a prezzo 0 da salvare sul DB var item2save = bomList .Where(x => x.Price == 0) .ToList(); List listInserted = new List(); // ciclo x ogni elemento della BOM, cercando x gruppo e ExtItemCode foreach (var item in item2save) { var currRec = dbCtx .DbSetItem .Where(x => x.CodGroup == item.ClassCode && x.ExtItemCode == item.ItemCode) .FirstOrDefault(); // se nullo --> verifico x inserire!!! if (currRec == null) { // verifico NON sia tra gli list2upd già in fase di inserimento if (!listInserted.Any(x => x.CodGroup == item.ClassCode && x.ExtItemCode == item.ItemCode)) { ItemModel newRec = new ItemModel() { CodGroup = item.ClassCode, ItemType = Core.Enums.ItemClassType.Bom, IsService = false, // da calcolare meglio x gruppo ItemCode = 0, ExtItemCode = item.ItemCode, SupplCode = "BOM ITEM", Description = $"BOM | {item.ClassCode} | {item.ItemCode}", Cost = 0, Margin = 0, QtyMin = 0, QtyMax = 0, UM = "#" }; dbCtx.DbSetItem.Add(newRec); listInserted.Add(newRec); } } } return await dbCtx.SaveChangesAsync() > 0; } #endregion Public Methods } }