using EgwCoreLib.Lux.Core.RestPayload; using EgwCoreLib.Lux.Data.DbModel.Utils; using EgwCoreLib.Lux.Data.DbModel.Sales; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Newtonsoft.Json; using NLog; using NLog.LayoutRenderers; using static EgwCoreLib.Lux.Core.Enums; using EgwCoreLib.Lux.Data.DbModel.Items; using EgwCoreLib.Lux.Data.DbModel.Config; namespace EgwCoreLib.Lux.Data.Controllers { internal class LuxController { // manca costruttore parametrico contoller... #region Internal Methods /// /// Elenco completo Config Glass /// /// internal async Task> ConfGlassGetAllAsync() { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = await dbCtx .DbSetConfGlass .ToListAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante ConfGlassGetAllAsync{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco completo Config Profile /// /// internal async Task> ConfProfileGetAllAsync() { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = await dbCtx .DbSetConfProfile .ToListAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante ConfProfileGetAllAsync{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco completo Config Wood /// /// internal async Task> ConfWoodGetAllAsync() { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = await dbCtx .DbSetConfWood .ToListAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante ConfWoodGetAllAsync{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco completo Customers da DB /// /// internal List CustomersGetAll() { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = dbCtx .DbSetCustomer .ToList(); } catch (Exception exc) { Log.Error($"Eccezione durante CustomersGetAll{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco completo Dealers da DB /// /// internal List DealersGetAll() { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = dbCtx .DbSetDealer .ToList(); } catch (Exception exc) { Log.Error($"Eccezione durante DealersGetAll{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Esegue eliminazione /// /// /// internal async Task GenClassDeleteAsync(GenClassModel rec2del) { bool answ = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { var dbResult = dbCtx .DbSetGenClass .Where(x => x.ClassCod == rec2del.ClassCod) .FirstOrDefault(); var numChild = dbCtx .DbSetGenVal .Count(x => x.ClassCod == rec2del.ClassCod); // se trovato e NON HA record child --> elimino if (dbResult != null && numChild == 0) { dbCtx.DbSetGenClass.Remove(dbResult); await dbCtx.SaveChangesAsync(); } } catch (Exception exc) { Log.Error($"Eccezione durante GenClassDeleteAsync{Environment.NewLine}{exc}"); } } return answ; } /// /// Elenco completo GenClass /// /// internal async Task> GenClassGetAllAsync() { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = await dbCtx .DbSetGenClass .Include(o => o.GenValNav) .ToListAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante GenClassGetAllAsync{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Upsert record GenClass /// /// /// internal async Task GenClassUpsertAsync(GenClassModel upsRec) { bool answ = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { var currRec = dbCtx .DbSetGenClass .Where(x => x.ClassCod == upsRec.ClassCod) .FirstOrDefault(); // se trovato --> aggiorno if (currRec != null) { currRec.Description = upsRec.Description; dbCtx.Entry(currRec).State = EntityState.Modified; } // se mancasse --> aggiungo else { dbCtx.DbSetGenClass.Add(upsRec); } // salvo... int numAct = await dbCtx.SaveChangesAsync(); answ = numAct > 0; } catch (Exception exc) { Log.Error($"Eccezione durante GenClassUpsertAsync{Environment.NewLine}{exc}"); } } return answ; } /// /// Esegue eliminazione /// /// /// internal async Task GenValDeleteAsync(GenValueModel rec2del) { bool answ = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { var dbResult = dbCtx .DbSetGenVal .Where(x => x.GenValID == rec2del.GenValID) .FirstOrDefault(); // se trovato --> elimino e sposto i rimanenti... if (dbResult != null) { // modifico record successivi... var list2Move = dbCtx .DbSetGenVal .Where(x => x.ClassCod == rec2del.ClassCod && x.Ordinal > dbResult.Ordinal) .ToList(); foreach (var item in list2Move) { item.Ordinal--; dbCtx.Entry(item).State = EntityState.Modified; } // elimino dbCtx.DbSetGenVal.Remove(dbResult); // salvo tutto await dbCtx.SaveChangesAsync(); } } catch (Exception exc) { Log.Error($"Eccezione durante GenValDeleteAsync{Environment.NewLine}{exc}"); } } return answ; } /// /// Elenco valori x classe richiesta /// /// /// internal async Task> GenValGetFiltAsync(string codClass) { List dbResult = new List(); if (!string.IsNullOrEmpty(codClass)) { //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = await dbCtx .DbSetGenVal .Where(x => x.ClassCod == codClass) .ToListAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante GenValGetFiltAsync{Environment.NewLine}{exc}"); } } } return dbResult; } /// /// Esegue spostamento nell'ordinamento relativo alla classe /// NB: verifica spostamento sia ammissibile: se primo rec non "sale", se ultimo non "scende"... /// /// /// /// internal async Task GenValMoveAsync(GenValueModel selRec, bool moveUp) { bool answ = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { var currRec = dbCtx .DbSetGenVal .Where(x => x.GenValID == selRec.GenValID) .FirstOrDefault(); if (currRec != null) { // recupero info del num rec del suo gruppo int numRec = dbCtx .DbSetGenVal .Count(x => x.ClassCod == selRec.ClassCod); // verifico NON sia primo/ultimo... bool canMove = false; int newPos = moveUp ? currRec.Ordinal - 1 : currRec.Ordinal + 1; if (moveUp) { canMove = newPos > 0; } else { canMove = newPos <= numRec; } // se abilitato --> aggiorno i 2 record... if (canMove) { var otherRec = dbCtx .DbSetGenVal .Where(x => x.ClassCod == selRec.ClassCod && x.Ordinal == newPos) .FirstOrDefault(); if (otherRec != null) { otherRec.Ordinal = currRec.Ordinal; dbCtx.Entry(otherRec).State = EntityState.Modified; currRec.Ordinal = newPos; dbCtx.Entry(currRec).State = EntityState.Modified; } // salvo... int numAct = await dbCtx.SaveChangesAsync(); answ = numAct > 0; } } } catch (Exception exc) { Log.Error($"Eccezione durante GenValMoveAsync{Environment.NewLine}{exc}"); } } return answ; } /// /// Esegue Upsert del record ricevuto /// /// /// internal async Task GenValUpsertAsync(GenValueModel upsRec) { bool answ = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { var currRec = dbCtx .DbSetGenVal .Where(x => x.GenValID == upsRec.GenValID) .FirstOrDefault(); // se trovato --> aggiorno if (currRec != null) { currRec.ValString = upsRec.ValString; dbCtx.Entry(currRec).State = EntityState.Modified; } // se mancasse --> aggiungo else { dbCtx.DbSetGenVal.Add(upsRec); } // salvo... int numAct = await dbCtx.SaveChangesAsync(); answ = numAct > 0; } catch (Exception exc) { Log.Error($"Eccezione durante GenValUpsertAsync{Environment.NewLine}{exc}"); } } return answ; } /// /// Eliminazione record item /// /// /// internal async Task ItemDeleteAsync(ItemModel rec2del) { bool result = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { var dbResult = await dbCtx .DbSetItem .Where(x => x.ItemID == rec2del.ItemID) .FirstOrDefaultAsync(); if (dbResult != null) { dbCtx.DbSetItem.Remove(dbResult); await dbCtx.SaveChangesAsync(); } } catch (Exception exc) { Log.Error($"Eccezione durante ItemDeleteAsync{Environment.NewLine}{exc}"); } } return result; } /// /// Elenco completo Items /// /// internal List ItemGetAll() { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = dbCtx .DbSetItem .ToList(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemGetAll{Environment.NewLine}{exc}"); } } return dbResult; } #if false /// /// Elenco item Child da ID Parent (per sostituzione) /// /// ID parent (valido quindi >0) /// internal List ItemGetChild(int ItemIdParent) { List dbResult = new List(); if (ItemIdParent > 0) { //using (DataLayerContext dbCtx = new DataLayerContext(configuration)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = dbCtx .DbSetItem .Where(x => x.ItemID == ItemIdParent || x.ItemIDParent == ItemIdParent) .ToList(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemGetChild{Environment.NewLine}{exc}"); } } } return dbResult; } #endif /// /// Elenco item alternativi da ID di un record (per sostituzione) /// /// ID item corrente (valido quindi >0) /// internal List ItemGetAlt(int ItemId) { List dbResult = new List(); if (ItemId > 0) { //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { // cerco singolo record x partire... var currRec = dbCtx .DbSetItem .Where(x => x.ItemID == ItemId) .FirstOrDefault(); if ((currRec != null)) { // se è un record che ha parentId > 0 --> cerco da quello record analoghi + parent if (currRec.ItemIDParent > 0) { dbResult = dbCtx .DbSetItem .Where(x => x.ItemID == currRec.ItemIDParent || x.ItemIDParent == currRec.ItemIDParent) .ToList(); } // altrimenti cerco child collegati else { dbResult = dbCtx .DbSetItem .Where(x => x.ItemID == currRec.ItemID || x.ItemIDParent == currRec.ItemID) .ToList(); } } } catch (Exception exc) { Log.Error($"Eccezione durante ItemGetAlt{Environment.NewLine}{exc}"); } } } return dbResult; } /// /// Elenco item da ricerca filtro x gruppo/tipo /// /// /// /// internal List ItemGetFilt(string CodGroup, ItemClassType ItemType) { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = dbCtx .DbSetItem .Where(x => (string.IsNullOrEmpty(CodGroup) || x.CodGroup == CodGroup) && (ItemType == ItemClassType.ND || x.ItemType == ItemType)) .ToList(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemGetFilt{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco item da ricerca completa /// /// /// /// /// internal List ItemGetFilt(string CodGroup, ItemClassType ItemType, string SearchVal) { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = dbCtx .DbSetItem .Where(x => (string.IsNullOrEmpty(CodGroup) || x.CodGroup == CodGroup) && (ItemType == ItemClassType.ND || x.ItemType == ItemType) && (string.IsNullOrEmpty(SearchVal) || x.Description.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase) || x.ExtItemCode.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase) || x.SupplCode.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase)) ) .ToList(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemGetFilt{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco item da ricerca filtro x gruppo/tipo Async /// /// /// /// /// internal async Task> ItemGetFiltAsync(string CodGroup, ItemClassType ItemType) { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = await dbCtx .DbSetItem .Where(x => (string.IsNullOrEmpty(CodGroup) || x.CodGroup == CodGroup) && (ItemType == ItemClassType.ND || x.ItemType == ItemType)) .Include(g => g.ItemGroupNav) .ToListAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemGetFiltAsync{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco item da ricerca completa Async /// /// /// /// /// internal async Task> ItemGetFiltAsync(string CodGroup, ItemClassType ItemType, string SearchVal) { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = await dbCtx .DbSetItem .Where(x => (string.IsNullOrEmpty(CodGroup) || x.CodGroup == CodGroup) && (ItemType == ItemClassType.ND || x.ItemType == ItemType) && (string.IsNullOrEmpty(SearchVal) || x.Description.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase) || x.ExtItemCode.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase) || x.SupplCode.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase)) ) .ToListAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemGetFiltAsync{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco item da ricerca /// /// /// internal List ItemGetSearch(string SearchVal) { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = dbCtx .DbSetItem .Where(x => x.Description.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase) || x.ExtItemCode.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase) || x.SupplCode.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase)) .ToList(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemGetSearch{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco item da ricerca async /// /// /// internal async Task> ItemGetSearchAsync(string SearchVal) { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = await dbCtx .DbSetItem .Where(x => x.Description.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase) || x.ExtItemCode.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase) || x.SupplCode.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase)) .ToListAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemGetSearchAsync{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco completo ItemGroup gestiti /// /// internal List ItemGroupGetAll() { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = dbCtx .DbSetItemGroup .ToList(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemGroupGetAllAsync{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco completo ItemGroup gestiti async /// /// internal async Task> ItemGroupGetAllAsync() { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = await dbCtx .DbSetItemGroup .ToListAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemGroupGetAllAsync{Environment.NewLine}{exc}"); } } return dbResult; } internal bool ItemUpsert(ItemModel newRec) { bool answ = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { var currRec = dbCtx .DbSetItem .Where(x => x.ItemID == newRec.ItemID) .FirstOrDefault(); // se trovato --> aggiorno if (currRec != null) { currRec.Description = newRec.Description; currRec.SupplCode = newRec.SupplCode; currRec.ItemCode = newRec.ItemCode; currRec.Cost = newRec.Cost; currRec.Description = newRec.Description; currRec.IsService = newRec.IsService; currRec.Margin = newRec.Margin; dbCtx.Entry(currRec).State = EntityState.Modified; } // se mancasse --> aggiungo else { dbCtx.DbSetItem.Add(newRec); } // salvo... dbCtx.SaveChanges(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemGetSearch{Environment.NewLine}{exc}"); } } return answ; } /// /// Inserisce o aggiorna il record /// /// /// internal async Task ItemUpsertAsync(ItemModel currRec) { bool result = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { var dbResult = await dbCtx .DbSetItem .Where(x => x.ItemID == currRec.ItemID) .FirstOrDefaultAsync(); if (dbResult != null) { //dbCtx.DbSetItem.Remove(dbResult); dbResult.CodGroup = currRec.CodGroup; dbResult.ItemType = currRec.ItemType; dbResult.IsService = currRec.IsService; dbResult.ItemCode = currRec.ItemCode; dbResult.ExtItemCode = currRec.ExtItemCode; dbResult.Cost = currRec.Cost; dbResult.Margin = currRec.Margin; dbResult.Description = currRec.Description; dbResult.QtyMin = currRec.QtyMin; dbResult.QtyMax = currRec.QtyMax; dbResult.UM = currRec.UM; dbCtx.Entry(dbResult).State = EntityState.Modified; } else { dbCtx.DbSetItem.Add(currRec); } await dbCtx.SaveChangesAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemUpsertAsync{Environment.NewLine}{exc}"); } } return result; } /// /// Upsert item ricevuti da BOM calcolata /// /// /// internal bool ItemUpsertFromBom(List bomList) { bool answ = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { // prendo solo elementi a prezzo 0 da salvare sul DB var item2save = bomList .Where(x => x.Price == 0) .ToList(); // 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 --> lo devo inserire!!! if (currRec == null) { 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); } } // salvo... dbCtx.SaveChanges(); } catch (Exception exc) { Log.Error($"Eccezione durante ItemUpsertFromBom{Environment.NewLine}{exc}"); } } return answ; } /// /// Elenco completo offerte da DB /// /// internal async Task> OfferGetAll() { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = await dbCtx .DbSetOffer .Include(c => c.CustomerNav) .Include(d => d.DealerNav) .Include(o => o.OfferRowNav) .ToListAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante OfferGetAll{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Elenco righe offerta specificata /// /// /// internal List OfferRowGetByOffer(int OfferID) { List dbResult = new List(); //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { dbResult = dbCtx .DbSetOfferRow .Where(x => x.OfferID == OfferID) .Include(s => s.SellingItemNav) //.Include(d => d.DealerNav) .ToList(); } catch (Exception exc) { Log.Error($"Eccezione durante OfferRowGetByOffer{Environment.NewLine}{exc}"); } } return dbResult; } /// /// Effettua update dei costi di tutte le righe dell'offerta indicata /// /// ID riga offerta da aggiornare /// Bom aggiornata da salvare /// internal async Task OffertRowUpdateBom(int OfferRowID, List newBomList) { bool answ = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { // recupero riga offerta da aggiornare... var currRec = dbCtx .DbSetOfferRow .Where(x => x.OfferRowID == OfferRowID) .FirstOrDefault(); // se è valida --> procedo! if (currRec != null) { // recupero l'elenco degli itemGroup gestiti var itemGroupList = dbCtx .DbSetItemGroup .ToList(); // recupero il subset item da BOM / BomAlt... var bomGenList = dbCtx .DbSetItem .Where(x => (x.ItemType == Core.Enums.ItemClassType.Bom || x.ItemType == Core.Enums.ItemClassType.BomAlt)) .ToList(); // calcolo il NUOVO costo e lo aggiorno... double totCost = 0; double totPrice = 0; int numGroupOk = 0; int numItemOk = 0; int numElems = newBomList.Count; // validazione e completamento BOM validateBom(itemGroupList, bomGenList, ref newBomList, null, ref totCost, ref totPrice, ref numGroupOk, ref numItemOk); // salvo BOM... string itemBom = JsonConvert.SerializeObject(newBomList); currRec.ItemBOM = itemBom; // salvo arrotondato alla 3° decimale currRec.BomCost = Math.Round(totCost, 3); currRec.BomPrice = Math.Round(totPrice, 3); currRec.BomOk = numElems == numGroupOk; currRec.ItemOk = numElems == numItemOk; dbCtx.Entry(currRec).State = EntityState.Modified; } // salvo modifiche... await dbCtx.SaveChangesAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante OffertRowUpdateBom{Environment.NewLine}{exc}"); } } return answ; } /// /// Effettua update dei costi di tutte le righe dell'offerta indicata /// /// /// internal async Task OffertUpdateCost(int OfferID) { bool answ = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { // recupero righe offerta... var offRowList = dbCtx .DbSetOfferRow .Where(x => x.OfferID == OfferID) .ToList(); // recupero l'elenco degli itemGroup gestiti var itemGroupList = dbCtx .DbSetItemGroup .ToList(); // recupero il subset item da BOM / BomAlt... var bomGenList = dbCtx .DbSetItem .Where(x => (x.ItemType == Core.Enums.ItemClassType.Bom || x.ItemType == Core.Enums.ItemClassType.BomAlt)) .ToList(); // ciclo! foreach (var currRec in offRowList) { // se contiene qualcosa x BOM... if (!string.IsNullOrEmpty(currRec.ItemBOM) && currRec.ItemBOM.Length > 2) { // deserializzo var bomList = JsonConvert.DeserializeObject>(currRec.ItemBOM); // se ho trovato elementi... if (bomList != null) { // calcolo il NUOVO costo e lo aggiorno... double totCost = 0; double totPrice = 0; int numGroupOk = 0; int numItemOk = 0; int numElems = bomList.Count; // validazione e completamento BOM validateBom(itemGroupList, bomGenList, ref bomList, null, ref totCost, ref totPrice, ref numGroupOk, ref numItemOk); // salvo BOM... string itemBom = JsonConvert.SerializeObject(bomList); currRec.ItemBOM = itemBom; // salvo arrotondato alla 3° decimale currRec.BomCost = Math.Round(totCost, 3); currRec.BomPrice = Math.Round(totPrice, 3); currRec.BomOk = numElems == numGroupOk; currRec.ItemOk = numElems == numItemOk; dbCtx.Entry(currRec).State = EntityState.Modified; } } } // salvo TUTTI i cambiamenti... await dbCtx.SaveChangesAsync(); } catch (Exception exc) { Log.Error($"Eccezione durante OffertUpdateCost{Environment.NewLine}{exc}"); } } return answ; } /// /// Esegue upsert del record offerta data la BOM ricevuta /// /// /// internal bool OfferUpsertFromBom(string uID, List bomList) { bool answ = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) using (DataLayerContext dbCtx = new DataLayerContext()) { try { var currRec = dbCtx .DbSetOfferRow .Where(x => x.OfferRowUID == uID) .FirstOrDefault(); // se trovato --> salvo BOM e calcolo costi if (currRec != null) { // recupero l'elenco degli itemGroup gestiti var itemGroupList = dbCtx .DbSetItemGroup .ToList(); // recupero il subset item da BOM... var bomGenList = dbCtx .DbSetItem //.Where(x => x.ItemType == Core.Enums.ItemClassType.Bom) .Where(x => (x.ItemType == Core.Enums.ItemClassType.Bom || x.ItemType == Core.Enums.ItemClassType.BomAlt)) .ToList(); // recupero la BOM list precedente var bomListPrev = JsonConvert.DeserializeObject>(currRec.ItemBOM); // calcolo il NUOVO costo e lo aggiorno... double totCost = 0; double totPrice = 0; int numGroupOk = 0; int numItemOk = 0; int numElems = bomList.Count; // validazione e completamento BOM validateBom(itemGroupList, bomGenList, ref bomList, bomListPrev, ref totCost, ref totPrice, ref numGroupOk, ref numItemOk); // salvo BOM... string itemBom = JsonConvert.SerializeObject(bomList); currRec.ItemBOM = itemBom; // salvo arrotondato alla 3° decimale currRec.BomCost = Math.Round(totCost, 3); currRec.BomPrice = Math.Round(totPrice, 3); currRec.BomOk = numElems == numGroupOk; currRec.ItemOk = numElems == numItemOk; dbCtx.Entry(currRec).State = EntityState.Modified; } // salvo... dbCtx.SaveChanges(); } catch (Exception exc) { Log.Error($"Eccezione durante OfferUpsertFromBom{Environment.NewLine}{exc}"); } } return answ; } #endregion Internal Methods #region Private Fields private static IConfiguration _configuration; private static Logger Log = LogManager.GetCurrentClassLogger(); #endregion Private Fields #region Private Methods /// /// Esegue completamento e la validazione dei dati BOM da lista articoli + gruppi, /// validando i dati stessi /// /// Elenco ItemGroup da considerare /// Item di tipo BOM/BomAlt AMMESSI /// Lista BOM ricevuta da validare /// Lista BOM precedente da confrontare x scelta alternativi /// Costo netto componenti BOM calcolato /// Prezzo complessivo calcolato (con aggiunta marginalità) /// Controllo coerenza calcoli sui gruppi items /// Controllo coerenza calcoli su num items private static void validateBom(List itemGroupList, List bomGenList, ref List bomList, List? bomListPrev, ref double totCost, ref double totPrice, ref int numGroupOk, ref int numItemOk) { double margin = 0; // ciclo x ogni elemento della BOM, cercando x gruppo e ExtItemCode foreach (var item in bomList) { // init del margine margin = 0; // verifico item group esistente... if (itemGroupList.Where(x => x.CodGroup == item.ClassCode).Count() > 0) { numGroupOk++; } // 2025.09.16: se il prezzo arriva dalla BOM calcolata uso quello... if (item.Price > 0) { // resetto ItemID ma NON il prezzo item.ItemID = 0; // conto l'item numItemOk++; item.PriceEff = item.Price; // dovrei recuperare margine da BOM... da rivedere, x ora cablato 20%... margin = 0.2; } else { /************************************************* * Ricerca costo item: * - se ho un itemID --> cerco record ESATTO e sostituisco descrizioni & co... * - se non ho itemID --> cerco dati di selezione + qtyRange *************************************************/ ItemModel? recCost = null; bool selExact = item.ItemID > 0; if (selExact) { recCost = bomGenList .Where(x => x.ItemID == item.ItemID) .FirstOrDefault(); } else { recCost = bomGenList .Where(x => x.CodGroup == item.ClassCode && x.ItemIDParent == 0 // voglio NON sia un record CHILD && x.ExtItemCode == item.ItemCode && item.Qty >= x.QtyMin && item.Qty < x.QtyMax) .OrderByDescending(x => x.Cost) .FirstOrDefault(); // 2025.09.24: se ho un elenco item della BOM precedente if (bomListPrev != null && bomListPrev.Count > 0 && recCost != null) { // ...cerco item trovato come PARENT di altri item var listAlt = bomGenList.Where(x => x.ItemIDParent == recCost.ItemID).ToList(); // che cerco nella nella BOM precedente... var result = listAlt .Join( bomListPrev, l1 => l1.ItemID, l2 => l2.ItemID, (l1, l2) => l1) .ToList(); // nel caso ne trovassi solo 1 uso quello al posto del recCost... if (result.Count == 1) { recCost = result.FirstOrDefault(); } } } // se trovato valorizzo! if (recCost != null) { numItemOk++; item.ItemID = recCost.ItemID; //item.PriceEff = recCost.BomCost * (1 + recCost.Margin); item.PriceEff = recCost.Cost; // se selezione esatta sovrascrivo altri valori if (selExact) { item.ItemCode = recCost.ExtItemCode; //item.DescriptionCode = recCost.Name; } margin = recCost.Margin; } else { item.ItemID = 0; item.PriceEff = 0; } } // ...e aggiorno totale totCost += item.TotalCost; // e prezzo totale compreso margine totPrice += item.TotalCost * (1 + margin); } } #endregion Private Methods } }