diff --git a/Directory.Packages.props b/Directory.Packages.props index fd14e937..4ea68f3c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -8,8 +8,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + diff --git a/EgwCoreLib.Lux.Data/Controllers/LuxController.cs b/EgwCoreLib.Lux.Data/Controllers/LuxController.cs index ef91f0c6..53c8ae6e 100644 --- a/EgwCoreLib.Lux.Data/Controllers/LuxController.cs +++ b/EgwCoreLib.Lux.Data/Controllers/LuxController.cs @@ -1,5 +1,4 @@ -using EgwCoreLib.Lux.Core.Generic; -using EgwCoreLib.Lux.Core.RestPayload; +using EgwCoreLib.Lux.Core.RestPayload; using EgwCoreLib.Lux.Data.DbModel.Items; using EgwCoreLib.Lux.Data.DbModel.Job; using EgwCoreLib.Lux.Data.DbModel.Production; @@ -220,204 +219,6 @@ namespace EgwCoreLib.Lux.Data.Controllers } #endif - /// - /// Add record del solo ProdEstimate - /// - /// - /// -#if false - - internal async Task 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 listMaccCurr = currWLD.MachineCalcResults.Select(x => x.Name).OrderBy(x => x).ToList() ?? new List(); - 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 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 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 considerando 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 listProdGroup2Add = new List(); - // 1: non lavorabili... - if (currWLD.ListUnWorkable.Count > 0) - { - // calcolo il dizionario degli elementi... - Dictionary 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 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; - } - - /// - /// Validazione record: - /// - controllo state vs estimate - /// - segnala il numero dei record aggiornati - /// - /// Elenco record da verificare - internal async Task OrderRowListValidate(List 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; - } -#endif - /// /// Elenco record Fasi da DB /// @@ -442,6 +243,7 @@ namespace EgwCoreLib.Lux.Data.Controllers return dbResult; } +#if false /// /// Add record di un singolo ProdGroup da fase Balance /// @@ -515,7 +317,8 @@ namespace EgwCoreLib.Lux.Data.Controllers } } return answ; - } + } +#endif #if true /// @@ -602,106 +405,6 @@ namespace EgwCoreLib.Lux.Data.Controllers } #endif - -#if false - /// - /// Esegue merge dei dati nella tab profili del DB con le info accessorie... - /// - /// - /// - /// - /// - internal async Task 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 list2check = JsonConvert.DeserializeObject>(rawContent) ?? new List(); - List rec2ins = new List(); - 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; - } -#endif - -#if false - /// - /// Salvataggio info serializzate x soglie e dati opzionali sul DB - /// - /// - /// - /// - /// - /// - /// - internal async Task 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; - } -#endif - /// /// Elenco da DB delel stats aggregate dato periodo inizio/fine /// diff --git a/EgwCoreLib.Lux.Data/Repository/Production/IProductionGroupRepository.cs b/EgwCoreLib.Lux.Data/Repository/Production/IProductionGroupRepository.cs index 439505ec..1cb0b6ae 100644 --- a/EgwCoreLib.Lux.Data/Repository/Production/IProductionGroupRepository.cs +++ b/EgwCoreLib.Lux.Data/Repository/Production/IProductionGroupRepository.cs @@ -9,5 +9,6 @@ namespace EgwCoreLib.Lux.Data.Repository.Production Task> GetByOrderStateAsync(OrderStates reqState); + Task UpsertBalanceAsync(string uID, string rGroup, string rawBalance); } } diff --git a/EgwCoreLib.Lux.Data/Repository/Production/ProductionGroupRepository.cs b/EgwCoreLib.Lux.Data/Repository/Production/ProductionGroupRepository.cs index cbc7a3d8..75189754 100644 --- a/EgwCoreLib.Lux.Data/Repository/Production/ProductionGroupRepository.cs +++ b/EgwCoreLib.Lux.Data/Repository/Production/ProductionGroupRepository.cs @@ -1,5 +1,7 @@ -using EgwCoreLib.Lux.Data.DbModel.Production; +using EgwCoreLib.Lux.Core.Generic; +using EgwCoreLib.Lux.Data.DbModel.Production; using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; using static EgwCoreLib.Lux.Core.Enums; namespace EgwCoreLib.Lux.Data.Repository.Production @@ -45,6 +47,87 @@ namespace EgwCoreLib.Lux.Data.Repository.Production .ToListAsync(); } + /// + /// Add record di un singolo ProdGroup da fase Balance + /// + /// UID dell'item offerta di cui si è ricevuto l'oggetto Balance' + /// Prod Group di riferimento + /// + public async Task UpsertBalanceAsync(string uID, string rGroup, string rawBalance) + { + bool answ = false; + // Add validation for null or empty list + if (string.IsNullOrWhiteSpace(uID) || + string.IsNullOrWhiteSpace(rGroup) || + string.IsNullOrWhiteSpace(rawBalance)) + { + return answ; + } + + await using var dbCtx = await CreateContextAsync(); + await using var tx = dbCtx.Database.BeginTransaction(); + try + { + // Tentativo di deserializzazione + var data = JsonConvert.DeserializeObject>(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... + answ = await dbCtx.SaveChangesAsync() > 0; + } + } + return answ; + } + catch + { + tx.Rollback(); + throw; + } + } + #endregion Public Methods } } \ No newline at end of file diff --git a/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs b/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs index 46ce82e4..9113d8a8 100644 --- a/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs +++ b/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs @@ -56,6 +56,7 @@ namespace EgwCoreLib.Lux.Data.Services public IConfProfileService ConfProfServ => _serviceProvider.GetRequiredService(); public IOfferRowService OfferRowServ => _serviceProvider.GetRequiredService(); public IOrderRowService OrderRowServ => _serviceProvider.GetRequiredService(); + public IProductionGroupService PrGrpServ => _serviceProvider.GetRequiredService(); public IProductionOdlService PrOdlServ => _serviceProvider.GetRequiredService(); #endregion Public Properties @@ -343,29 +344,10 @@ namespace EgwCoreLib.Lux.Data.Services /// public async Task SaveHmlAsync(string uID, Constants.EXECENVIRONMENTS execEnvironment, string rawContent) { + // non effettuo salvataggio sul DB perché master del dato è esterno e lo lasceremo solo in cache REDIS + await Task.Delay(1); using var activity = StartActivity(); - string source = "DB"; - // salvo sul DB il risultato della BOM - if (!string.IsNullOrEmpty(rawContent)) - { - try - { - // non effettuo salvataggio sul DB perché master del dato è esterno e lo lasceremo solo in cache REDIS - await Task.Delay(1); - } - catch (Exception exc) - { - string exMsg = $"Eccezione durante SaveHmlAsync | uID: {uID} | envir: {execEnvironment}"; - LogTrace($"{exMsg}{Environment.NewLine}{exc}", LogLevel.Error); - // traccio errore - activity?.SetStatus(ActivityStatusCode.Error, exc.Message); - activity?.AddEvent(new ActivityEvent("exception", tags: new ActivityTagsCollection { - { "exception.type", exc.GetType().Name }, - { "exception.message", exc.Message }, - { "exception.stacktrace", exc.StackTrace } - })); - } - } + string source = "NONE"; activity?.SetTag("data.source", source); LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms"); } @@ -378,18 +360,10 @@ namespace EgwCoreLib.Lux.Data.Services /// Environment dell'item /// Stima Balance serializzata /// - public async Task SaveProdBalanceAsync(string uID, string rGroup, Constants.EXECENVIRONMENTS execEnvironment, string balance) + public async Task SaveProdBalanceAsync(string uID, string rGroup, Constants.EXECENVIRONMENTS execEnvironment, string balance) { - using var activity = StartActivity(); - string source = "DB"; - // salvo sul DB il risultato della BOM - if (!string.IsNullOrEmpty(balance)) - { - // salvo info balance nel record del DB relativo all'oggetto richiesto - await dbController.ProdGroupUpsertBalance(uID, rGroup, balance); - } - activity?.SetTag("data.source", source); - LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms"); + var result = await PrGrpServ.UpsertBalanceAsync(uID, rGroup, balance); + return result; } /// @@ -638,29 +612,6 @@ namespace EgwCoreLib.Lux.Data.Services private new static Logger Log = LogManager.GetCurrentClassLogger(); private readonly IServiceProvider _serviceProvider; -#if false - - /// - /// Validazione record: - /// - controllo state vs estimate - /// - segnala il numero dei record aggiornati - /// - /// Elenco record da verificare - public async Task OrderRowListValidate(List list2chk) - { - using var activity = StartActivity(); - string source = "DB+REDIS"; - // calcolo - int numDone = await dbController.OrderRowListValidate(list2chk); - // svuoto cache... - await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:Orders:*"); - await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OrderRows:*"); - await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OrderRowsByState:*"); - activity?.SetTag("data.source", source); - LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms"); - return numDone; - } -#endif private string redisBaseKey = "Lux:Cache"; #endregion Private Fields diff --git a/EgwCoreLib.Lux.Data/Services/Production/IProductionGroupService.cs b/EgwCoreLib.Lux.Data/Services/Production/IProductionGroupService.cs index 55c18be0..40631011 100644 --- a/EgwCoreLib.Lux.Data/Services/Production/IProductionGroupService.cs +++ b/EgwCoreLib.Lux.Data/Services/Production/IProductionGroupService.cs @@ -8,5 +8,7 @@ namespace EgwCoreLib.Lux.Data.Services.Production Task> GetByOrderRowAsync(int orderRowID); Task> GetByOrderStateAsync(OrderStates reqState); + + Task UpsertBalanceAsync(string uID, string rGroup, string rawBalance); } } diff --git a/EgwCoreLib.Lux.Data/Services/Production/ProductionGroupService.cs b/EgwCoreLib.Lux.Data/Services/Production/ProductionGroupService.cs index ed25f471..6bfb300f 100644 --- a/EgwCoreLib.Lux.Data/Services/Production/ProductionGroupService.cs +++ b/EgwCoreLib.Lux.Data/Services/Production/ProductionGroupService.cs @@ -47,6 +47,36 @@ namespace EgwCoreLib.Lux.Data.Services.Production }); } + /// + /// Esegue salvataggio ProdBalance (di un gruppo lavorazioni per riga ordine) sul DB + /// + /// UID dell'item offerta di cui si è ricevuto l'oggetto Balance' + /// Prod Group di riferimento + /// Environment dell'item + /// Stima Balance serializzata + /// + public async Task UpsertBalanceAsync(string uID, string rGroup, string rawBalance) + { + return await TraceAsync($"{_className}.UpsertBalance", async (activity) => + { + string operation = "UpsertBalance"; + bool success = false; + + if (string.IsNullOrWhiteSpace(uID) || string.IsNullOrWhiteSpace(rGroup) || string.IsNullOrWhiteSpace(rawBalance)) + return false; + + success = await _repo.UpsertBalanceAsync(uID, rGroup, rawBalance); + + activity?.SetTag("db.operation", operation); + if (success) + { + await ClearCacheAsync($"{_redisBaseKey}:{_className}"); + } + + return success; + }); + } + #endregion Public Methods #region Private Fields diff --git a/Lux.API/Lux.API.csproj b/Lux.API/Lux.API.csproj index 3d3542d8..02fc2115 100644 --- a/Lux.API/Lux.API.csproj +++ b/Lux.API/Lux.API.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - 1.1.2603.2008 + 1.1.2603.2010 diff --git a/Lux.UI/Components/Compo/OfferRowMan.razor.cs b/Lux.UI/Components/Compo/OfferRowMan.razor.cs index 906b7adf..5471e147 100644 --- a/Lux.UI/Components/Compo/OfferRowMan.razor.cs +++ b/Lux.UI/Components/Compo/OfferRowMan.razor.cs @@ -1461,7 +1461,7 @@ namespace Lux.UI.Components.Compo CurrData = new LivePayload() { CurrJwd = currJwd, - SvgPreview = currSvg + SvgPreview = "" //currSvg }; } diff --git a/Lux.UI/Components/Compo/Templates/TemplateRowList.razor.cs b/Lux.UI/Components/Compo/Templates/TemplateRowList.razor.cs index ecdedd54..ecf6803f 100644 --- a/Lux.UI/Components/Compo/Templates/TemplateRowList.razor.cs +++ b/Lux.UI/Components/Compo/Templates/TemplateRowList.razor.cs @@ -1042,7 +1042,7 @@ namespace Lux.UI.Components.Compo.Templates CurrData = new LivePayload() { CurrJwd = currJwd, - SvgPreview = currSvg + SvgPreview = "" //currSvg }; } diff --git a/Lux.UI/Lux.UI.csproj b/Lux.UI/Lux.UI.csproj index ab94178b..979ac68a 100644 --- a/Lux.UI/Lux.UI.csproj +++ b/Lux.UI/Lux.UI.csproj @@ -5,7 +5,7 @@ enable enable aspnet-Lux.UI-a758c101-a2f4-4e38-977d-1c4887dbbd50 - 1.1.2603.2008 + 1.1.2603.2010 diff --git a/Resources/ChangeLog.html b/Resources/ChangeLog.html index 4f491d88..98101281 100644 --- a/Resources/ChangeLog.html +++ b/Resources/ChangeLog.html @@ -1,6 +1,6 @@ LUX - Web Windows MES -

Versione: 1.1.2603.2008

+

Versione: 1.1.2603.2010


Note di rilascio:
  • diff --git a/Resources/VersNum.txt b/Resources/VersNum.txt index e6b25d04..af7c0f8c 100644 --- a/Resources/VersNum.txt +++ b/Resources/VersNum.txt @@ -1 +1 @@ -1.1.2603.2008 +1.1.2603.2010 diff --git a/Resources/manifest.xml b/Resources/manifest.xml index 97f31f99..995f6add 100644 --- a/Resources/manifest.xml +++ b/Resources/manifest.xml @@ -1,6 +1,6 @@ - 1.1.2603.2008 + 1.1.2603.2010 http://nexus.steamware.net/repository/SWS/GPW/stable/GPW.UI.zip http://nexus.steamware.net/repository/SWS/GPW/stable/ChangeLog.html false