Files
lux/EgwCoreLib.Lux.Data/Controllers/LuxController.cs
T
2026-03-17 18:33:05 +01:00

2498 lines
106 KiB
C#

using EgwCoreLib.Lux.Core.Generic;
using EgwCoreLib.Lux.Core.RestPayload;
using EgwCoreLib.Lux.Data.DbModel.Config;
using EgwCoreLib.Lux.Data.DbModel.Cost;
using EgwCoreLib.Lux.Data.DbModel.Items;
using EgwCoreLib.Lux.Data.DbModel.Job;
using EgwCoreLib.Lux.Data.DbModel.Production;
using EgwCoreLib.Lux.Data.DbModel.Sales;
using EgwCoreLib.Lux.Data.DbModel.Stats;
using EgwCoreLib.Lux.Data.DbModel.Utils;
using EgwCoreLib.Lux.Data.Domains;
using EgwMultiEngineManager.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using MySqlConnector;
using Newtonsoft.Json;
using NLog;
using StackExchange.Redis;
using System.Data;
using static EgwCoreLib.Lux.Core.Enums;
namespace EgwCoreLib.Lux.Data.Controllers
{
internal class LuxController
{
// manca costruttore parametrico contoller...
#region Internal Methods
/// <summary>
/// Elenco CostDrivers
/// </summary>
/// <returns></returns>
internal async Task<List<CostDriverModel>> CostDriverGetAllAsync()
{
List<CostDriverModel> dbResult = new List<CostDriverModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = await dbCtx
.DbSetCostDriver
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante CostDriverGetAllAsync{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Elenco contatori
/// </summary>
/// <param name="yearRef">Anno riferimento, se null da tutti</param>
/// <returns></returns>
internal async Task<List<CounterModel>> CountersGetAllAsync(int? yearRef = null)
{
List<CounterModel> dbResult = new List<CounterModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = await dbCtx
.DbSetCounters
.Where(x => yearRef == null || x.RefYear == yearRef)
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante CountersGetAllAsync | yearRef: {yearRef}{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Recupera un nuovo valore del contatore per tipo ed anno richiesto, se mancasse crea
/// </summary>
/// <param name="yearRef">Anno riferimento</param>
/// <param name="countName">Counter richiesto</param>
/// <returns></returns>
internal async Task<int> CountersGetNext(int yearRef, string countName)
{
int newCount = 0;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
var outParam = new MySqlParameter("@pValue", MySqlDbType.Int32)
{
Direction = ParameterDirection.Output
};
await dbCtx.Database.ExecuteSqlRawAsync(
"CALL GetNextCounter(@pYear, @pName, @pValue);",
new MySqlParameter("@pYear", yearRef),
new MySqlParameter("@pName", countName),
outParam
);
if (outParam != null)
{
int.TryParse($"{outParam.Value}", out newCount);
}
}
return newCount;
}
/// <summary>
/// Elenco completo Customers da DB
/// </summary>
/// <returns></returns>
internal List<CustomerModel> CustomersGetAll()
{
List<CustomerModel> dbResult = new List<CustomerModel>();
//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;
}
/// <summary>
/// Elenco completo Dealers da DB
/// </summary>
/// <returns></returns>
internal List<DealerModel> DealersGetAll()
{
List<DealerModel> dbResult = new List<DealerModel>();
//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;
}
/// <summary>
/// Add item ricevuti da BOM calcolata
/// </summary>
/// <param name="bomList"></param>
/// <returns></returns>
internal bool ItemUpsertFromBom(List<BomItemDTO> bomList)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// Controllo ed inserisco eventuali gruppi mancanti
UpdateCodGroup(bomList);
// prendo solo elementi a prezzo 0 da salvare sul DB
var item2save = bomList
.Where(x => x.Price == 0)
.ToList();
List<ItemModel> listInserted = new List<ItemModel>();
// 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);
}
}
}
// salvo...
dbCtx.SaveChanges();
}
return answ;
}
/// <summary>
/// Elenco item da ricerca filtro x gruppo/tipo
/// </summary>
/// <param name="CodGroup"></param>
/// <param name="ItemType"></param>
/// <returns></returns>
internal List<ItemModel> ItemGetFilt(string CodGroup, ItemClassType ItemType)
{
List<ItemModel> dbResult = new List<ItemModel>();
//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;
}
/// <summary>
/// Elenco completo ItemGroup gestiti
/// </summary>
/// <returns></returns>
internal List<ItemGroupModel> ItemGroupGetAll()
{
List<ItemGroupModel> dbResult = new List<ItemGroupModel>();
//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;
}
/// <summary>
/// Elenco completo ItemGroup gestiti async
/// </summary>
/// <returns></returns>
internal async Task<List<ItemGroupModel>> ItemGroupGetAllAsync()
{
List<ItemGroupModel> dbResult = new List<ItemGroupModel>();
//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 async Task<bool> OffersCheckExpired()
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
DateTime adesso = DateTime.Now;
// recupero offerta...
var listExpired = dbCtx
.DbSetOffer
.Where(x => x.ValidUntil < adesso && x.OffertState == OfferStates.Open)
.ToList();
// se trovo le aggiorno come stato
if (listExpired != null)
{
foreach (var item in listExpired)
{
item.OffertState = OfferStates.Expired;
dbCtx.Entry(item).State = EntityState.Modified;
}
// salvo TUTTI i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OffersCheckExpired{Environment.NewLine}{exc}");
}
}
return answ;
}
#if true
/// <summary>
/// Recupera da DB riga offerta dato Primary ID
/// </summary>
/// <param name="OfferRowID"></param>
/// <returns></returns>
internal async Task<OfferRowModel?> OfferRowGetByIdAsync(int OfferRowID)
{
OfferRowModel? dbResult = null;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
dbResult = await dbCtx
.DbSetOfferRow
.Include(s => s.SellingItemNav)
.FirstOrDefaultAsync(x => x.OfferRowID == OfferRowID);
}
return dbResult;
}
/// <summary>
/// Elenco righe offerta specificata
/// </summary>
/// <param name="OfferID"></param>
/// <returns></returns>
internal List<OfferRowModel> OfferRowGetByOffer(int OfferID)
{
List<OfferRowModel> dbResult = new List<OfferRowModel>();
//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;
}
/// <summary>
/// Recupera da DB riga offerta dato UID
/// </summary>
/// <param name="OfferRowUID"></param>
/// <returns></returns>
internal OfferRowModel? OfferRowGetByUID(string OfferRowUID)
{
OfferRowModel? dbResult = null;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = dbCtx
.DbSetOfferRow
.Include(s => s.SellingItemNav)
.FirstOrDefault(x => x.OfferRowUID == OfferRowUID);
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OfferRowGetByUID{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// Elimina riga e sposta eventuali righe successive...
/// </summary>
/// <param name="rec2Del"></param>
/// <returns></returns>
internal async Task<bool> OffertRowDelete(OfferRowModel rec2Del)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero offerta...
var currRec = dbCtx
.DbSetOfferRow
.Where(x => x.OfferRowID == rec2Del.OfferRowID)
.FirstOrDefault();
// se non trovo aggiungo
if (currRec != null)
{
// recupero indice attuale...
int currRowNum = rec2Del.RowNum;
// cerco righe successive
var list2move = dbCtx
.DbSetOfferRow
.Where(x => x.OfferID == rec2Del.OfferID && x.RowNum > currRowNum)
.ToList();
// se ci sono aggiorno!
if (list2move != null && list2move.Count > 0)
{
foreach (var item in list2move)
{
item.RowNum--;
dbCtx.Entry(item).State = EntityState.Modified;
}
}
// infine rimuovo riga
dbCtx.DbSetOfferRow.Remove(currRec);
}
// salvo TUTTI i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OffertRowDelete{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Aggiornamento valore ImgType da tipo Prodotto sellingItem ancestor
/// </summary>
/// <param name="offertID"></param>
/// <returns></returns>
internal async Task<bool> OffertRowFixImgTypeAsync(int offertID)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
var currList = await dbCtx
.DbSetOfferRow
.Where(x => x.OfferID == offertID)
.Include(s => s.SellingItemNav)
.ToListAsync();
// se trovato --> verifico valori differenti, aggiorno e restituisco da calcolare
if (currList != null)
{
var list2fix = currList.Where(x => x.ImgType == ImageType.ND).ToList();
if (list2fix != null && list2fix.Count > 0)
{
// sistemo ImgType
foreach (var item in list2fix)
{
// se è calcolato il selling item --> img calcolata
if (item.SellingItemNav != null && (item.SellingItemNav.SourceType == ItemSourceType.Jwd || item.SellingItemNav.SourceType == ItemSourceType.FileBTL))
item.ImgType = ImageType.Calculated;
dbCtx.Entry(item).State = EntityState.Modified;
}
// salvo...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
}
}
return answ;
}
/// <summary>
/// Aggiornamento valore UID non calcolato + ritorno elenco UID da aggiornare
/// </summary>
/// <param name="offertID"></param>
/// <returns></returns>
internal async Task<List<string>> OffertRowFixUidAsync(int offertID)
{
List<string> answ = new List<string>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
var currList = await dbCtx
.DbSetOfferRow
.Where(x => x.OfferID == offertID)
.ToListAsync();
// se trovato --> verifico valori differenti, aggiorno e restituisco da calcolare
if (currList != null)
{
var list2fix = currList.Where(x => string.IsNullOrEmpty(x.OfferRowUID) || x.OfferRowUID != x.OfferRowDtx).ToList();
if (list2fix != null && list2fix.Count > 0)
{
// salvo elenco
answ = list2fix.Select(x => x.OfferRowDtx).ToList();
// sistemo UID
foreach (var item in list2fix)
{
item.OfferRowUID = item.OfferRowDtx;
dbCtx.Entry(item).State = EntityState.Modified;
}
// salvo...
var result = await dbCtx.SaveChangesAsync();
}
}
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OffertRowFixUidAsync{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Effettua update stato await BOM/PRICE per l'offerta indicata
/// </summary>
/// <param name="offerRowID">ID singola riga offerta</param>
/// <param name="awaitBom">Se non nullo è il nuovo stato await BOM</param>
/// <param name="awaitPrice">Se non nullo è stato await Price</param>
/// <returns></returns>
internal async Task<bool> OffertRowUpdateAwaitStateAsync(int offerRowID, bool? awaitBom, bool? awaitPrice)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero righe offerta...
var currRec = dbCtx
.DbSetOfferRow
.Where(x => x.OfferRowID == offerRowID)
.FirstOrDefault();
// aggiorno parametri (se inviati)
if (currRec != null)
{
currRec.AwaitBom = awaitBom ?? currRec.AwaitBom;
currRec.AwaitPrice = awaitPrice ?? currRec.AwaitPrice;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OffertRowUpdateAwaitStateAsync{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Effettua update dei costi di tutte le righe dell'offerta indicata
/// </summary>
/// <param name="OfferRowID">ID riga offerta da aggiornare</param>
/// <param name="newBomList">Bom aggiornata da salvare</param>
/// <returns></returns>
internal async Task<bool> OffertRowUpdateBom(int OfferRowID, List<BomItemDTO> 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 totItemQty = 0;
int numGroupOk = 0;
int numItemOk = 0;
int numElems = newBomList.Count;
// validazione e completamento BOM
BomCalculator.Validate(itemGroupList, bomGenList, ref newBomList, null, ref totCost, ref totPrice, ref totItemQty, 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;
currRec.ProdItemQty = totItemQty;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo modifiche...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OffertRowUpdateBom{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Aggiorno sul DB i dati del file associato
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
internal async Task<bool> OffertRowUpdateFileDataAsync(OfferRowModel updRec)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// recupero righe offerta...
var currRec = await dbCtx
.DbSetOfferRow
.Where(x => x.OfferRowID == updRec.OfferRowID)
.FirstOrDefaultAsync();
// aggiorno parametri (se inviati)
if (currRec != null)
{
currRec.FileName = updRec.FileName;
currRec.FileResource = updRec.FileResource;
currRec.FileSize = updRec.FileSize;
currRec.SerStruct = updRec.SerStruct;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
return answ;
}
/// <summary>
/// Effettua update serStruct per l'offerta indicata
/// </summary>
/// <param name="offerRowID">ID singola riga offerta</param>
/// <param name="serStruct">Valore serializzatoe</param>
/// <returns></returns>
internal async Task<bool> OffertRowUpdateSerStruct(int offerRowID, string serStruct)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero righe offerta...
var currRec = dbCtx
.DbSetOfferRow
.Where(x => x.OfferRowID == offerRowID)
.FirstOrDefault();
// aggiorno parametri (se inviati)
if (currRec != null)
{
currRec.SerStruct = serStruct;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OffertRowUpdateSerStruct{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Add record riga offerta
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
internal async Task<bool> OffertRowUpsertAsync(OfferRowModel updRec)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// recupero offerta...
var currRec = await dbCtx
.DbSetOfferRow
.Where(x => x.OfferRowID == updRec.OfferRowID)
.FirstOrDefaultAsync();
// se non trovo aggiungo
if (currRec == null)
{
dbCtx.DbSetOfferRow.Add(updRec);
// se ci sono record successivi li devo spostare...
var list2move = await dbCtx
.DbSetOfferRow
.Where(x => x.OfferID == updRec.OfferID && x.RowNum >= updRec.RowNum)
.ToListAsync();
if (list2move != null && list2move.Count > 0)
{
foreach (var item2move in list2move)
{
item2move.RowNum++;
dbCtx.Entry(item2move).State = EntityState.Modified;
}
}
}
// altrimenti aggiorno
else
{
dbCtx.Entry(currRec).CurrentValues.SetValues(updRec);
}
// salvo TUTTI i cambiamenti...
int result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
return answ;
}
#endif
/// <summary>
/// Esegue upsert del record offerta data la BOM ricevuta
/// </summary>
/// <param name="uID"></param>
/// <param name="bomList"></param>
internal bool OfferUpsertFromBom(string uID, List<BomItemDTO> 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.sourceType == 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<List<BomItemDTO>>(currRec.ItemBOM);
// calcolo il NUOVO costo e lo aggiorno...
double totCost = 0;
double totPrice = 0;
int totItemQty = 0;
int numGroupOk = 0;
int numItemOk = 0;
int numElems = bomList.Count;
// validazione e completamento BOM
BomCalculator.Validate(itemGroupList, bomGenList, ref bomList, bomListPrev, ref totCost, ref totPrice, ref totItemQty, 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;
// setto ok await di BOM e Price
currRec.AwaitBom = false;
currRec.AwaitPrice = false;
currRec.ProdItemQty = totItemQty;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo...
var result = dbCtx.SaveChanges();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OfferUpsertFromBom{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Elimina riga e sposta eventuali righe successive...
/// </summary>
/// <param name="rec2Del"></param>
/// <returns></returns>
internal async Task<bool> OrderRowDelete(OrderRowModel rec2Del)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero offerta...
var currRec = dbCtx
.DbSetOrderRow
.Where(x => x.OrderRowID == rec2Del.OrderRowID)
.FirstOrDefault();
// se trovo procedo
if (currRec != null)
{
// recupero indice attuale...
int currRowNum = rec2Del.RowNum;
// cerco righe successive
var list2move = dbCtx
.DbSetOrderRow
.Where(x => x.OrderID == rec2Del.OrderID && x.RowNum > currRowNum)
.ToList();
// se ci sono aggiorno!
if (list2move != null && list2move.Count > 0)
{
foreach (var item in list2move)
{
item.RowNum--;
dbCtx.Entry(item).State = EntityState.Modified;
}
}
// infine rimuovo riga
dbCtx.DbSetOrderRow.Remove(currRec);
}
// salvo TUTTI i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowDelete{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Aggiornamento valore UID non calcolato + ritorno elenco UID da aggiornare
/// </summary>
/// <param name="orderID"></param>
/// <returns></returns>
internal List<string> OrderRowFixUid(int orderID)
{
List<string> answ = new List<string>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
var currList = dbCtx
.DbSetOrderRow
.Where(x => x.OrderID == orderID)
.ToList();
// se trovato --> verifico valori differenti, aggiorno e restituisco da calcolare
if (currList != null)
{
var list2fix = currList.Where(x => string.IsNullOrEmpty(x.OrderRowUID) || x.OrderRowUID != x.OrderRowCode).ToList();
if (list2fix != null && list2fix.Count > 0)
{
// salvo elenco
answ = list2fix.Select(x => x.OrderRowCode).ToList();
// sistemo UID
foreach (var item in list2fix)
{
item.OrderRowUID = item.OrderRowCode;
dbCtx.Entry(item).State = EntityState.Modified;
}
// salvo...
var result = dbCtx.SaveChanges();
}
}
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowFixUid{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Elenco righe Ordine specificato
/// </summary>
/// <param name="OrderID"></param>
/// <returns></returns>
internal List<OrderRowModel> OrderRowGetByOffer(int OrderID)
{
List<OrderRowModel> dbResult = new List<OrderRowModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = dbCtx
.DbSetOrderRow
.Where(x => x.OrderID == OrderID)
.Include(s => s.SellingItemNav)
//.Include(d => d.DealerNav)
.ToList();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowGetByOffer{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Elenco righe ordine dato stato richiesto
/// </summary>
/// <param name="reqState"></param>
/// <returns></returns>
internal List<OrderRowModel> OrderRowGetByState(OrderStates reqState, DateTime dtStart, DateTime dtEnd)
{
List<OrderRowModel> dbResult = new List<OrderRowModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = dbCtx
.DbSetOrderRow
.Where(x => x.OrderRowState == reqState && x.Inserted >= dtStart && x.Inserted <= dtEnd)
.Include(s => s.SellingItemNav)
//.Include(d => d.DealerNav)
.ToList();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowGetByState{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Elenco righe ordine dato periodo + stato richiesto MINIMO
/// </summary>
/// <param name="reqState"></param>
/// <returns></returns>
internal List<OrderRowModel> OrderRowGetByStateMin(OrderStates reqState, DateTime dtStart, DateTime dtEnd)
{
List<OrderRowModel> dbResult = new List<OrderRowModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = dbCtx
.DbSetOrderRow
.Where(x => x.OrderRowState >= reqState && x.Inserted >= dtStart && x.Inserted <= dtEnd)
.Include(s => s.SellingItemNav)
//.Include(d => d.DealerNav)
.ToList();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowGetByStateMin{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Riga Ordine dato suo UID
/// </summary>
/// <param name="OrderRowUID"></param>
/// <returns></returns>
internal OrderRowModel OrderRowGetByUID(string OrderRowUID)
{
OrderRowModel? dbResult = null;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = dbCtx
.DbSetOrderRow
.Include(s => s.SellingItemNav)
.FirstOrDefault(x => x.OrderRowUID == OrderRowUID);
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowGetByUID{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Validazione record:
/// - controllo state vs estimate
/// - segnala il numero dei record aggiornati
/// </summary>
/// <param name="list2chk">Elenco record da verificare</param>
internal async Task<int> OrderRowListValidate(List<OrderRowModel> list2chk)
{
int numDone = 0;
// verifica preliminare: serve SSE stato e estimate non corrispondono...
var list2fix = list2chk
.Where(x => x.OrderRowState == OrderStates.Created && !string.IsNullOrEmpty(x.ProdEstimate))
.ToList();
if (list2fix.Any())
{
// per ogni record processo intera validazione
foreach (var item in list2fix)
{
bool fatto = await OrderRowUpsertProdEst(item.OrderRowUID, item.ProdEstimate);
numDone += fatto ? 1 : 0;
}
}
return numDone;
}
/// <summary>
/// Effettua update stato await BOM/PRICE per l'Ordine indicato
/// </summary>
/// <param name="orderRowID">ID singola riga ordine</param>
/// <param name="awaitBom">Se non nullo è il nuovo stato await BOM</param>
/// <param name="awaitPrice">Se non nullo è stato await Price</param>
/// <returns></returns>
internal async Task<bool> OrderRowUpdateAwaitState(int orderRowID, bool? awaitBom, bool? awaitPrice)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero righe ordine...
var currRec = dbCtx
.DbSetOrderRow
.Where(x => x.OrderRowID == orderRowID)
.FirstOrDefault();
// aggiorno parametri (se inviati)
if (currRec != null)
{
currRec.AwaitBom = awaitBom ?? currRec.AwaitBom;
currRec.AwaitPrice = awaitPrice ?? currRec.AwaitPrice;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowUpdateAwaitState{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Aggiorno sul DB i dati del file associato
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
internal async Task<bool> OrderRowUpdateFileData(OrderRowModel updRec)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero righe offerta...
var currRec = dbCtx
.DbSetOrderRow
.Where(x => x.OrderRowID == updRec.OrderRowID)
.FirstOrDefault();
// aggiorno parametri (se inviati)
if (currRec != null)
{
currRec.FileName = updRec.FileName;
currRec.FileResource = updRec.FileResource;
currRec.FileSize = updRec.FileSize;
currRec.SerStruct = updRec.SerStruct;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowUpdateFileData{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Effettua update serStruct per l'Ordine indicato
/// </summary>
/// <param name="orderRowID">ID singola riga Ordine</param>
/// <param name="serStruct">Valore serializzatoe</param>
/// <returns></returns>
internal async Task<bool> OrderRowUpdateSerStruct(int orderRowID, string serStruct)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero righe offerta...
var currRec = dbCtx
.DbSetOrderRow
.Where(x => x.OrderRowID == orderRowID)
.FirstOrDefault();
// aggiorno parametri (se inviati)
if (currRec != null)
{
currRec.SerStruct = serStruct;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowUpdateSerStruct{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Aggiorna stato riga ordine
/// </summary>
/// <param name="orderRowID"></param>
/// <param name="reqState"></param>
/// <returns></returns>
internal async Task<bool> OrderRowUpdateState(int orderRowID, OrderStates reqState)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero righe offerta...
var currRec = dbCtx
.DbSetOrderRow
.Where(x => x.OrderRowID == orderRowID)
.FirstOrDefault();
// aggiorno parametri (se inviati)
if (currRec != null)
{
currRec.OrderRowState = reqState;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowUpdateState{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Add riga ordine
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
internal async Task<bool> OrderRowUpsert(OrderRowModel updRec)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero offerta...
var currRec = dbCtx
.DbSetOrderRow
.Where(x => x.OrderRowID == updRec.OrderRowID)
.FirstOrDefault();
// se non trovo aggiungo
if (currRec == null)
{
dbCtx.DbSetOrderRow.Add(updRec);
// se ci sono record successivi li devo spostare...
var list2move = dbCtx
.DbSetOrderRow
.Where(x => x.OrderID == updRec.OrderID && x.RowNum >= updRec.RowNum)
.ToList();
if (list2move != null && list2move.Count > 0)
{
foreach (var item2move in list2move)
{
item2move.RowNum++;
dbCtx.Entry(item2move).State = EntityState.Modified;
}
}
}
// altrimenti aggiorno
else
{
dbCtx.Entry(currRec).CurrentValues.SetValues(updRec);
}
// salvo TUTTI i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowUpsert{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Add record del solo ProdEstimate
/// </summary>
/// <param name="uID"></param>
/// <param name="prodEstim"></param>
internal async Task<bool> OrderRowUpsertProdEst(string uID, string prodEstim)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero offerta...
var currRec = dbCtx
.DbSetOrderRow
.Where(x => x.OrderRowUID == uID)
.FirstOrDefault();
// se trovo aggiorno
if (currRec != null)
{
// genero WLD x controllo
var currWLD = new WorkLoadDetailDTO(currRec.OrderRowUID, currRec.ProdEstimate);
// faccio update in cascata dei record collegati x macchine e items
var listMachDb = dbCtx
.DbSetProdPlant
.Select(x => x.ProdPlantCod)
.ToList();
List<string> listMaccCurr = currWLD.MachineCalcResults.Select(x => x.Name).OrderBy(x => x).ToList() ?? new List<string>();
if (listMaccCurr != null && listMaccCurr.Any())
{
var listDiff = listMaccCurr.Except(listMachDb).ToList();
if (listDiff.Any())
{
foreach (var macch in listDiff)
{
dbCtx
.DbSetProdPlant
.Add(new ProductionPlantModel() { ProdPlantCod = macch, ProdPlantDescript = macch });
}
}
}
// resetta assegnazioni prodgroup agli items...
List<ProductionItemModel> listItem2upd = await dbCtx
.DbSetProdItem
.Where(x => x.OrderRowID == currRec.OrderRowID && x.ProdGroupID != null)
.ToListAsync();
if (listItem2upd != null && listItem2upd.Count > 0)
{
// li aggiorna tutti resettando ProdGroupID
listItem2upd.ForEach(x => x.ProdGroupID = null);
}
// elimina eventuali oggetti ProductionGroup precedenti
List<ProductionGroupModel> listProdGroup2Rem = await dbCtx
.DbSetProdGroup
.Where(x => x.OrderRowID == currRec.OrderRowID)
.ToListAsync();
// rimuovo...
if (listProdGroup2Rem != null && listProdGroup2Rem.Count > 0)
{
dbCtx.DbSetProdGroup.RemoveRange(listProdGroup2Rem);
}
/*----------------------------------
* Generazione ProdGroup
* FixMe ToDo !!!
*
* rifare onsiderando le REALI combinazioni scaturite x questo specifico caso e
* - ENUMERARE le combinazioni
* - ogni combinazione sarà un caso specifico tra 0...N dove N è il totale delle macchine gestite
* - i successivi calcoli di balance/stima saranno fatti x questo SPECIFICO ID GROUP così da fare prima... a sto punto GroupIP potrebbe essere un int 0...n oppure l'id del record... forse meglio il counter 0..n
*
* */
int grpIdx = 1;
// preparo x add nuovi ProductionGroup da analisi ritorno stime
List<ProductionGroupModel> listProdGroup2Add = new List<ProductionGroupModel>();
// 1: non lavorabili...
if (currWLD.ListUnWorkable.Count > 0)
{
// calcolo il dizionario degli elementi...
Dictionary<string, ProdMachineDetailDto> newWorkGroupList = new();
ProdMachineDetailDto detProd = new ProdMachineDetailDto()
{
TagList = currWLD.ListUnWorkable
};
newWorkGroupList.Add("", detProd);
string rawWGL = JsonConvert.SerializeObject(newWorkGroupList);
ProductionGroupModel newRec = new ProductionGroupModel()
{
OrderRowID = currRec.OrderRowID,
GrpIdx = grpIdx++,
WorkGroupListRaw = rawWGL
};
listProdGroup2Add.Add(newRec);
}
// dizionario x macchina delle parts LAVORABILI su impianto..
var machineTags = currWLD.MachineCalcResults
.ToDictionary(
m => m.Name,
m => m.PartList
.Where(p => p.CalcResult == EgwCoreLib.Lux.Core.Enums.PartVerificationResult.MACHINABLE)
.ToList()
);
// ciclo x tutte le combinazioni di gruppi lavorabilità...
foreach (var item in currWLD.LoadDetail)
{
// calcolo il dizionario degli elementi...
Dictionary<string, ProdMachineDetailDto> newWorkGroupList = new();
foreach (var machineName in item.Machines)
{
decimal effectiveTime = 0;
// Recuperiamo i dati della macchina dal dizionario
if (machineTags.TryGetValue(machineName, out var machineParts))
{
// Creiamo un set dei tag del gruppo per una ricerca veloce O(1)
var groupTagsSet = item.Tags.ToHashSet();
// Sommiamo il tempo solo per i pezzi che appartengono a questo gruppo
effectiveTime = machineParts
.Where(p => groupTagsSet.Contains(p.Tag))
.Sum(p => p.Time);
}
ProdMachineDetailDto detProd = new ProdMachineDetailDto()
{
TagList = item.Tags,
Time = effectiveTime // Tempo reale specifico per questa macchina/gruppo
};
newWorkGroupList.Add(machineName, detProd);
}
string rawWGL = JsonConvert.SerializeObject(newWorkGroupList);
ProductionGroupModel newRec = new ProductionGroupModel()
{
OrderRowID = currRec.OrderRowID,
GrpIdx = grpIdx++,
WorkGroupListRaw = rawWGL
};
listProdGroup2Add.Add(newRec);
}
// aggiungo i record...
dbCtx.DbSetProdGroup.AddRange(listProdGroup2Add);
// aggiorno info Estimation, tempi e stato
currRec.ProdEstimate = prodEstim;
if (!string.IsNullOrEmpty(prodEstim))
{
currRec.OrderRowState = OrderStates.Estimated;
}
var totEstim = listProdGroup2Add.Sum(x => x.TotalEstimTime);
currRec.ProdEstimTime = totEstim;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo TUTTI i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderRowUpsertProdEst{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Elenco record Fasi da DB
/// </summary>
/// <returns></returns>
internal async Task<List<PhaseModel>> PhasesGetAllAsync()
{
List<PhaseModel> dbResult = new List<PhaseModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = await dbCtx
.DbSetPhase
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante PhasesGetAllAsync{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Elenco record ProductionGroup dato OrderRow
/// </summary>
/// <returns></returns>
internal async Task<List<ProductionGroupModel>> ProdGroupByOrderRow(int OrderRowID)
{
List<ProductionGroupModel> dbResult = new List<ProductionGroupModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = await dbCtx
.DbSetProdGroup
.Where(x => x.OrderRowID == OrderRowID)
.Include(i => i.ItemsNav)
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProdGroupByOrderRow{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Elenco record ProductionGroup dato Stato dell'OrderRow
/// </summary>
/// <returns></returns>
internal async Task<List<ProductionGroupModel>> ProdGroupByOrderState(OrderStates reqState)
{
List<ProductionGroupModel> dbResult = new List<ProductionGroupModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = await dbCtx
.DbSetProdGroup
.Include(o => o.OrderRowNav)
.Where(x => x.OrderRowNav.OrderRowState == reqState)
.Include(i => i.ItemsNav)
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProdGroupByOrderState{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Add record di un singolo ProdGroup da fase Balance
/// </summary>
/// <param name="uID">UID dell'item offerta di cui si è ricevuto l'oggetto Balance'</param>
/// <param name="rGroup">Prod Group di riferimento</param>
/// <param name="rawBalance"></param>
internal async Task<bool> ProdGroupUpsertBalance(string uID, string rGroup, string rawBalance)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// Tentativo di deserializzazione
var data = JsonConvert.DeserializeObject<Dictionary<string, ProdMachineDetailDto>>(rawBalance);
// proseguo solo se è valida la deserializzazione...
if (data != null)
{
// Togliamo la 'G' e convertiamo in int (gestisce automaticamente "01" -> 1)
int grpIdx = int.Parse(rGroup.TrimStart('G'));
// recupero ord row (parent)...
var ordRowRec = dbCtx
.DbSetOrderRow
.Where(x => x.OrderRowUID == uID)
.FirstOrDefault();
if (ordRowRec != null)
{
// recupero record specifico
var currRec = dbCtx
.DbSetProdGroup
.Where(x => x.OrderRowID == ordRowRec.OrderRowID && x.GrpIdx == grpIdx)
.FirstOrDefault();
// se trovato aggiorno
if (currRec != null)
{
currRec.WorkGroupListRaw = rawBalance;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// altrimenti aggiungo
else
{
ProductionGroupModel newRec = new ProductionGroupModel()
{
OrderRowID = ordRowRec.OrderRowID,
GrpIdx = grpIdx,
WorkGroupListRaw = rawBalance
};
dbCtx
.DbSetProdGroup
.Add(newRec);
}
// segno ordine come Assigned se non lo fosse...
if (ordRowRec.OrderRowState != OrderStates.Assigned)
{
ordRowRec.OrderRowState = OrderStates.Assigned;
dbCtx.Entry(ordRowRec).State = EntityState.Modified;
}
// salvo TUTTI i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
}
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProdGroupUpsertBalance{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Assegnazione in blocco degli item agli ODL corrispondenti
/// </summary>
/// <param name="dbList"></param>
/// <param name="dictParts"></param>
/// <returns></returns>
internal async Task<int> ProdItem2ODL_AssignAsync(List<ProductionODLModel> dbList, Dictionary<(int phaseId, int resId, string machine, int index), List<string>> dictParts)
{
int totalCreated = 0;
using (DataLayerContext dbCtx = new DataLayerContext())
{
// 1. Recuperiamo tutti i ProdBatchID coinvolti per fare una sola query
List<int> batchIds = dbList.Select(o => o.ProdBatchID).Distinct().ToList();
if (batchIds != null && batchIds.Count > 0)
{
// 2. Carichiamo in memoria i ProdItem necessari (solo ID e Tag per risparmiare RAM)
var itemsList = await dbCtx.DbSetProdItem
.Where(x => batchIds.Contains(x.ProdBatchID ?? 0) && x.ProdItemTag != null && x.ProdItemTag != "")
.Select(x => new { x.ProdItemID, x.ProdItemTag })
.ToListAsync();
// 1. Usiamo il "!" (null-forgiving operator) dopo x.ProdItemTag
// perché il filtro .Where sopra garantisce che non sia null.
var itemLookup = itemsList
.GroupBy(x => x.ProdItemTag!)
.ToDictionary(
g => g.Key,
g => g.First().ProdItemID,
StringComparer.OrdinalIgnoreCase
);
using var transaction = await dbCtx.Database.BeginTransactionAsync();
try
{
var relationsToInsert = new List<ProductionItem2ODLModel>();
foreach (var odl in dbList)
{
var key = (odl.PhaseID ?? 0, odl.ResourceID ?? 0, odl.ProdPlantCod, odl.Index);
if (dictParts.TryGetValue(key, out List<string> tagList))
{
foreach (var tag in tagList)
{
// 3. Cerchiamo l'ID corrispondente al tag nel nostro lookup locale
if (itemLookup.TryGetValue(tag, out int realItemId))
{
relationsToInsert.Add(new ProductionItem2ODLModel
{
ProdODLID = odl.ProdODLID,
ProdItemID = realItemId,
DtAssign = DateTime.Now
});
}
else
{
//Log.Warning($"Tag {tag} non trovato nel database per i batch selezionati.");
}
}
}
}
if (relationsToInsert.Any())
{
await dbCtx.DbSetProdItem2ODL.AddRangeAsync(relationsToInsert);
totalCreated = relationsToInsert.Count;
await dbCtx.SaveChangesAsync();
}
await transaction.CommitAsync();
}
catch (Exception exc)
{
await transaction.RollbackAsync();
Log.Error($"Errore nel salvataggio relazioni ODL-Parts: {exc.Message}");
throw;
}
}
}
return totalCreated;
}
/// <summary>
/// Esegue assegnazione bulk dei ProdItem ad un unico ProdBatch parent (per ora totale x RigaOrd)
/// </summary>
/// <param name="OrderRowId"></param>
/// <param name="ProdBatchId"></param>
/// <returns></returns>
internal async Task<int> ProdItemBulkAssignProdBatch(int OrderRowId, int ProdBatchId)
{
int totalUpdated = 0;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
using var transaction = await dbCtx.Database.BeginTransactionAsync();
try
{
int rowsAffected = await dbCtx.DbSetProdItem
.Where(p => p.OrderRowID == OrderRowId)
.ExecuteUpdateAsync(setters => setters
.SetProperty(p => p.ProdBatchID, ProdBatchId)
);
totalUpdated += rowsAffected;
await transaction.CommitAsync();
}
catch (Exception exc)
{
await transaction.RollbackAsync();
Log.Error($"Eccezione durante ProdItemBulkAssignProdBatch{Environment.NewLine}{exc}");
//throw;
}
}
return totalUpdated;
}
/// <summary>
/// Esegue assegnazione bulk dei ProdItem ad un unico ProdGroup parent
/// </summary>
/// <param name="OrderRowId"></param>
/// <param name="ProdGroupId"></param>
/// <param name="itemsToAssign"></param>
/// <returns></returns>
internal async Task<int> ProdItemBulkAssignProdGroup(int OrderRowId, int ProdGroupId, Dictionary<string, double> itemsToAssign)
{
int totalUpdated = 0;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
using var transaction = await dbCtx.Database.BeginTransactionAsync();
try
{
foreach (var entry in itemsToAssign)
{
// Esegue un UPDATE diretto: UPDATE production_item SET ProdAssignID = x, EstimTime = y WHERE ProdItemTag = z
int rowsAffected = await dbCtx.DbSetProdItem
.Where(p => p.OrderRowID == OrderRowId && p.ProdItemTag == entry.Key)
.ExecuteUpdateAsync(setters => setters
.SetProperty(p => p.ProdGroupID, ProdGroupId)
.SetProperty(p => p.EstimTime, entry.Value)
);
totalUpdated += rowsAffected;
}
await transaction.CommitAsync();
}
catch (Exception exc)
{
await transaction.RollbackAsync();
Log.Error($"Eccezione durante ProdItemBulkAssignProdGroup{Environment.NewLine}{exc}");
//throw;
}
}
return totalUpdated;
}
/// <summary>
/// Elenco ProdItem dato OrderRow
/// </summary>
/// <param name="orderRowId"></param>
/// <returns></returns>
internal async Task<List<ProductionItemModel>> ProdItemByOrderRow(int orderRowId)
{
List<ProductionItemModel> dbResult = new List<ProductionItemModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = await dbCtx
.DbSetProdItem
.Where(x => x.OrderRowID == orderRowId)
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProdItemByOrderRow{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Reset impostazione ProdItem x ripartire senza setting ProdGroup
/// </summary>
/// <param name="orderRowID"></param>
/// <returns></returns>
internal async Task<int> ProdItemResetProdGroup(int orderRowID)
{
int numItem = 0;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
numItem = await dbCtx.DbSetProdItem
.Where(p => p.OrderRowID == orderRowID)
.ExecuteUpdateAsync(setters => setters
.SetProperty(p => p.ProdGroupID, (int?)null)
.SetProperty(p => p.EstimTime, 0)
);
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProdItemResetProdGroup{Environment.NewLine}{exc}");
}
}
return numItem;
}
/// <summary>
/// Elenco PODL non assegnati con struttura DTO appiattita
/// </summary>
/// <returns></returns>
internal async Task<List<OdlAssignDto>?> ProdOdlAssignGetAsync()
{
List<OdlAssignDto>? dbResults = null;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResults = await dbCtx.DbSetProdODL
.Where(x => !x.DateAssign.HasValue)
.Select(odl => new OdlAssignDto
{
Envir = odl.ProdBatchNav.Envir,
ProdODLID = odl.ProdODLID,
Description = odl.Description,
EstimTime = odl.EstimTime,
Index = odl.Index,
OdlTag = odl.OdlTag,
PhaseID = odl.PhaseID,
ProdBatchID = odl.ProdBatchID,
ProdPlantCod = odl.ProdPlantCod,
Qty = odl.Qty,
ResourceID = odl.ResourceID,
ItemList = odl.Item2OdlNav.Select(i => new ItemAssignDto
{
ProdItemID = i.ProdItemID,
OrderID = i.ProductionItemNav.OrderRowNav.OrderNav.OrderID,
OrderRowID = i.ProductionItemNav.OrderRowNav.OrderRowID,
OrderTag = i.ProductionItemNav.OrderRowNav.OrderNav.OrderCode,
OrderRowTag = i.ProductionItemNav.OrderRowNav.OrderRowCode,
ProdItemTag = i.ProductionItemNav.ProdItemTag ?? "***"
}).ToList()
})
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProductionOdlUnassignAsync{Environment.NewLine}{exc}");
}
}
return dbResults;
}
/// <summary>
/// Recupero record ProdOdl dato Tag/uID
/// </summary>
/// <param name="uID"></param>
/// <returns></returns>
internal async Task<ProductionODLModel?> ProdOdlGetByUidAsync(string uID)
{
ProductionODLModel? answ = null;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
answ = await dbCtx
.DbSetProdODL
.Where(x => x.OdlTag == uID)
.FirstOrDefaultAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProdOdlGetByUidAsync{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Aggiorna record ProdOdl (se trovato) con BOM (raw) ricevuta
/// </summary>
/// <param name="uID"></param>
/// <param name="bomRaw"></param>
/// <returns></returns>
internal async Task<bool> ProdOdlUpdateBomAsync(string uID, string bomRaw)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
var currRec = dbCtx
.DbSetProdODL
.Where(x => x.OdlTag == uID)
.FirstOrDefault();
// se trovato --> salvo BOM e calcolo costi
if (currRec != null)
{
currRec.RawBoM = bomRaw;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo...
var result = dbCtx.SaveChanges();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProdOdlUpdateBomAsync{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Aggiorna record ProdOdl (se trovato) con ItemListRaw (raw) inviata x calcolo PROD
/// </summary>
/// <param name="uID"></param>
/// <param name="itemListRaw"></param>
/// <returns></returns>
internal async Task<bool> ProdOdlUpdateItemRawAsync(string uID, string itemListRaw)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
var currRec = dbCtx
.DbSetProdODL
.Where(x => x.OdlTag == uID)
.FirstOrDefault();
// se trovato --> salvo BOM e calcolo costi
if (currRec != null)
{
currRec.RawItemRawList = itemListRaw;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo...
var result = dbCtx.SaveChanges();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProdOdlUpdateItemRawAsync{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Aggiorna record ProdOdl (se trovato) con RawMaterialList (raw) ricevuta da calcolo PROD
/// </summary>
/// <param name="uID"></param>
/// <param name="materialListRaw"></param>
/// <returns></returns>
internal async Task<bool> ProdOdlUpdateRawMaterialAsync(string uID, string materialListRaw)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
var currRec = dbCtx
.DbSetProdODL
.Where(x => x.OdlTag == uID)
.FirstOrDefault();
// se trovato --> salvo BOM e calcolo costi
if (currRec != null)
{
currRec.RawMaterials = materialListRaw;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
// salvo...
var result = dbCtx.SaveChanges();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProdOdlUpdateRawMaterialAsync{Environment.NewLine}{exc}");
}
}
return answ;
}
internal async Task<List<ProductionPlantModel>> ProdPlantGetAllAsync()
{
List<ProductionPlantModel> dbResult = new List<ProductionPlantModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = await dbCtx
.DbSetProdPlant
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProdPlantGetAllAsync{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Creazione di un Batch con relativo Tag e info x creazione ODL correlati
/// </summary>
/// <param name="newRec"></param>
/// <returns></returns>
internal async Task<ProductionBatchModel?> ProductionBatchCreateAsync(ProductionBatchModel newRec)
{
ProductionBatchModel dbResult = null;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// Definiamo i parametri di input
var pDesc = new MySqlParameter("@pDescription", newRec.Description ?? (object)DBNull.Value);
var pDate = new MySqlParameter("@pDueDate", newRec.DueDate);
var pPref = new MySqlParameter("@pPrefix", "BC.");
var pYear = new MySqlParameter("@pYear", newRec.DueDate.Year);
var pEnv = new MySqlParameter("@pEnv", newRec.Envir);
// Eseguiamo la procedura e mappiamo il risultato direttamente sul modello
// Nota: DbSetProdBatch deve essere configurato nel DbContext
var result = await dbCtx
.DbSetProdBatch
.FromSqlRaw("CALL stp_ProdBatch_insert(@pDescription, @pDueDate, @pPrefix, @pYear, @pEnv)", pDesc, pDate, pPref, pYear, pEnv)
.ToListAsync();
dbResult = result.FirstOrDefault() ?? new ProductionBatchModel();
}
catch (Exception ex)
{
throw new Exception("Errore durante ProductionBatchCreateAsync", ex);
}
return dbResult;
}
}
/// <summary>
/// Insert sul DB di un elenco ODL con calcolo della relativa KEY a cui poter, successivamente, collegare i record child (items)
/// </summary>
/// <param name="listOdl2ins"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
internal async Task<List<ProductionODLModel>> ProductionOdlCreateAsync(List<ProductionODLModel> listOdl2ins)
{
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// avvio transazione
using var transaction = await dbCtx.Database.BeginTransactionAsync();
try
{
int cYear = DateTime.Today.Year;
// insert in blocco
dbCtx.DbSetProdODL.AddRange(listOdl2ins);
// 3. Salvataggio massivo
// EF Core 8 ottimizzerà gli insert in batch dove possibile
await dbCtx.SaveChangesAsync();
// stored update Tags
var pProdBatchID = new MySqlParameter("@pDueDate", listOdl2ins.FirstOrDefault()?.ProdBatchID ?? 0);
var pPref = new MySqlParameter("@pPrefix", "ODL.");
var pYear = new MySqlParameter("@pYear", cYear);
await dbCtx.Database.ExecuteSqlRawAsync("CALL stp_ProdOdl_UpdateTag(@pProdBatchID, @pPrefix, @pYear)", pProdBatchID, pPref, pYear);
// 4. Conferma transazione
await transaction.CommitAsync();
// A questo punto, ogni oggetto in 'listOdl2ins' ha il ProdODLID aggiornato dal DB
return listOdl2ins;
}
catch (Exception ex)
{
await transaction.RollbackAsync();
// Logga l'errore secondo le tue necessità
throw new Exception("Errore durante la creazione massiva degli ODL", ex);
}
}
}
/// <summary>
/// Elenco PODL non assegnati
/// </summary>
/// <returns></returns>
internal async Task<List<ProductionODLModel>?> ProductionOdlUnassignAsync()
{
List<ProductionODLModel>? dbRestults = null;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbRestults = await dbCtx
.DbSetProdODL
.Where(x => !x.DateAssign.HasValue)
.Include(x => x.Item2OdlNav)
//.ThenInclude(i => i.ProductionItemNav)
//.ThenInclude(o => o.OrderRowNav)
//.ThenInclude(o => o.OrderNav)
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante ProductionOdlUnassignAsync{Environment.NewLine}{exc}");
}
}
return dbRestults;
}
/// <summary>
/// Esegue merge dei dati nella tab profili del DB con le info accessorie...
/// </summary>
/// <param name="uID"></param>
/// <param name="execEnvironment"></param>
/// <param name="rawContent"></param>
/// <returns></returns>
internal async Task<bool> SaveProfileListAsync(string uID, Constants.EXECENVIRONMENTS execEnvironment, string rawContent)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// solo se ho qualcosa da controllare...
if (!string.IsNullOrEmpty(rawContent))
{
// in primis recupero profili attuali
var dbList = await dbCtx
.DbSetConfProfile
.ToListAsync();
// ciclo sul contenuto ricevuto, se mancasse aggiungo!
List<string> list2check = JsonConvert.DeserializeObject<List<string>>(rawContent) ?? new List<string>();
List<ProfileModel> rec2ins = new List<ProfileModel>();
foreach (var item in list2check)
{
if (!dbList.Any(x => x.Code == item))
{
rec2ins.Add(new ProfileModel() { Code = item, Description = $"{item} - NEW" });
}
}
// se ho dati li inserisco...
if (rec2ins.Count > 0)
{
dbCtx.DbSetConfProfile.AddRange(rec2ins);
// salvo...
int numDone = await dbCtx.SaveChangesAsync();
answ = numDone > 0;
}
}
}
return answ;
}
/// <summary>
/// Salvataggio info serializzate x soglie e dati opzionali sul DB
/// </summary>
/// <param name="uID"></param>
/// <param name="execEnvironment"></param>
/// <param name="rawThreshold"></param>
/// <param name="rawData"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
internal async Task<bool> SaveProfileThreshAsync(string uID, Constants.EXECENVIRONMENTS execEnvironment, string rawThreshold, string rawData)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// solo se ho qualcosa da controllare...
if (!string.IsNullOrEmpty(rawThreshold) || !string.IsNullOrEmpty(rawData))
{
// in primis recupero profilo da aggiornare
var dbRec = await dbCtx
.DbSetConfProfile
.Where(x => x.Code == uID)
.FirstOrDefaultAsync();
// se ho record aggiorno...
if (dbRec != null)
{
dbRec.ProfDataRaw = rawData;
dbRec.ThreshDataRaw = rawThreshold;
dbCtx.Entry(dbRec).State = EntityState.Modified;
}
// alrimenti creo + aggiorno
else
{
dbCtx.DbSetConfProfile.Add(new ProfileModel()
{
Code = uID,
Description = $"{uID} - NEW PROFILE",
ProfDataRaw = rawData,
ThreshDataRaw = rawThreshold
});
}
// salvo...
int numDone = await dbCtx.SaveChangesAsync();
answ = numDone > 0;
}
}
return answ;
}
/// <summary>
/// Elenco da DB delel stats aggregate dato periodo inizio/fine
/// </summary>
/// <param name="dtStart"></param>
/// <param name="dtEnd"></param>
/// <returns></returns>
internal async Task<List<StatsAggregatedModel>> StatsAggrGetAsync(DateTime dtStart, DateTime dtEnd)
{
List<StatsAggregatedModel> answ = new List<StatsAggregatedModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// recupero ed ordino per data-ora
answ = await dbCtx
.DbSetStatsAggr
.Where(x => x.Hour >= dtStart && x.Hour <= dtEnd)
.AsNoTracking()
.OrderBy(x => x.Hour)
.ToListAsync();
}
return answ;
}
/// <summary>
/// Range periodo per chiamate aggregate
/// </summary>
/// <returns></returns>
internal async Task<Utils.DtUtils.Periodo> StatsAggrRangeAsync()
{
Utils.DtUtils.Periodo answ = new Utils.DtUtils.Periodo(Utils.DtUtils.PeriodSet.Today);
using (DataLayerContext dbCtx = new DataLayerContext())
{
var query = dbCtx.DbSetStatsAggr.AsQueryable();
var minHour = await query.MinAsync(x => x.Hour);
var maxHour = await query.MaxAsync(x => x.Hour);
answ.Inizio = minHour;
answ.Fine = maxHour;
return answ;
}
}
/// <summary>
/// Esegue insert statistiche aggregate sul DB
/// </summary>
/// <param name="listRecords">Elenco dei record da inserire</param>
/// <param name="removeOld">Se true preventivamente elimina record nel periodo richiesto</param>
/// <returns></returns>
internal async Task<long> StatsAggrUpsertAsync(List<StatsAggregatedModel> listRecords, bool removeOld)
{
int answ = 0;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// in primis se richiesto calcolo range periodo e svuoto...
if (removeOld)
{
var firstRec = listRecords.OrderBy(x => x.Hour).FirstOrDefault();
var lastRec = listRecords.OrderByDescending(x => x.Hour).FirstOrDefault();
if (firstRec != null && lastRec != null)
{
DateTime startDate = firstRec.Hour;
DateTime endDate = lastRec.Hour;
// uso direttamente ExecuteDelete
await dbCtx
.DbSetStatsAggr
.Where(x => x.Hour >= startDate && x.Hour <= endDate)
.ExecuteDeleteAsync();
}
}
// ora preparo inserimento massivo
await dbCtx
.DbSetStatsAggr
.AddRangeAsync(listRecords);
// salvo!
answ = await dbCtx.SaveChangesAsync();
// libero memoria del changeTracker
dbCtx.ChangeTracker.Clear();
}
return answ;
}
/// <summary>
/// Recupera dati stats di dettaglio dato filtro envir/tipo (opzionali) e periodo
/// </summary>
/// <param name="dtStart"></param>
/// <param name="dtEnd"></param>
/// <param name="sEnvir"></param>
/// <param name="sType"></param>
/// <returns></returns>
internal async Task<List<StatsDetailModel>> StatsDetailModelGetAsync(DateTime dtStart, DateTime dtEnd, string sEnvir = "", string sType = "")
{
List<StatsDetailModel> answ = new List<StatsDetailModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// recupero ed ordino per data-ora
var query = dbCtx.DbSetStatsDet
.Where(x => x.Hour >= dtStart && x.Hour <= dtEnd);
if (!string.IsNullOrEmpty(sEnvir))
query = query.Where(x => x.Environment == sEnvir);
if (!string.IsNullOrEmpty(sType))
query = query.Where(x => x.Type == sType);
answ = await query
.AsNoTracking()
.OrderBy(x => x.Hour)
.ThenBy(x => x.Environment)
.ThenBy(x => x.Type)
.ToListAsync();
}
return answ;
}
/// <summary>
/// Range periodo x chiamate detail eventualmente filtrate
/// </summary>
/// <param name="sEnvir"></param>
/// <param name="sType"></param>
/// <returns></returns>
internal async Task<Utils.DtUtils.Periodo> StatsDetailModelRangeAsync(string sEnvir, string sType)
{
Utils.DtUtils.Periodo answ = new Utils.DtUtils.Periodo(Utils.DtUtils.PeriodSet.Today);
using (DataLayerContext dbCtx = new DataLayerContext())
{
var query = dbCtx.DbSetStatsDet.AsQueryable();
if (!string.IsNullOrEmpty(sEnvir))
query = query.Where(x => x.Environment == sEnvir);
if (!string.IsNullOrEmpty(sType))
query = query.Where(x => x.Type == sType);
var minHour = await query.MinAsync(x => x.Hour);
var maxHour = await query.MaxAsync(x => x.Hour);
answ.Inizio = minHour;
answ.Fine = maxHour;
return answ;
}
}
/// <summary>
/// Esegue insert statistiche di dettaglio sul DB
/// </summary>
/// <param name="listRecords">Elenco dei record da inserire</param>
/// <param name="removeOld">Se true preventivamente elimina record nel periodo richiesto</param>
/// <returns></returns>
internal async Task<long> StatsDetailModelUpsertAsync(List<StatsDetailModel> listRecords, bool removeOld)
{
int answ = 0;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// in primis se richiesto calcolo range periodo e svuoto...
if (removeOld)
{
var firstRec = listRecords.OrderBy(x => x.Hour).FirstOrDefault();
var lastRec = listRecords.OrderByDescending(x => x.Hour).FirstOrDefault();
if (firstRec != null && lastRec != null)
{
DateTime startDate = firstRec.Hour;
DateTime endDate = lastRec.Hour;
// uso direttamente ExecuteDelete
await dbCtx
.DbSetStatsDet
.Where(x => x.Hour >= startDate && x.Hour <= endDate)
.ExecuteDeleteAsync();
}
}
// ora preparo inserimento massivo
await dbCtx
.DbSetStatsDet
.AddRangeAsync(listRecords);
// salvo!
answ = await dbCtx.SaveChangesAsync();
// libero memoria del changeTracker
dbCtx.ChangeTracker.Clear();
}
return answ;
}
/// <summary>
/// Elenco completo Tags
/// </summary>
/// <returns></returns>
internal async Task<List<TagsModel>> TagsGetAllAsync()
{
List<TagsModel> dbResult = new List<TagsModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = await dbCtx
.DbSetTags
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante TagsGetAllAsync{Environment.NewLine}{exc}");
}
}
return dbResult;
}
#if true
internal bool UpdateCodGroup(List<BomItemDTO> bomList)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// in primis calcolo i distinct dei CodGroup x eventuale insert preventivo
List<string> distCodGroups = bomList
.Select(i => i.ClassCode)
.Distinct()
.Where(c => !string.IsNullOrWhiteSpace(c))
.ToList();
// recupero l'elenco degli itemGroup gestiti
var itemGroupList = dbCtx
.DbSetItemGroup
.ToList();
// 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...
dbCtx.SaveChanges();
}
}
return answ;
}
#endif
#endregion Internal Methods
#region Private Fields
private static IConfiguration _configuration;
private static Logger Log = LogManager.GetCurrentClassLogger();
#endregion Private Fields
}
}