From efc06b7e235e3e740d046accae4e5245a6b3349d Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Fri, 19 Dec 2025 16:28:41 +0100 Subject: [PATCH] Update query x soglie dato profili --- EgwCoreLib.Lux.Data/DataLayerContext.cs | 21 ++++++- .../Production/ProductionAssignModel.cs | 63 ++++++++++++++++++- .../Production/ProductionPlannerModel.cs | 15 +++++ .../Services/ConfigDataService.cs | 21 ++++++- .../Services/DataLayerServices.cs | 27 +++++++- .../Services/ImageCacheService.cs | 18 +++++- Lux.API/Services/ExternalMessageProcessor.cs | 11 ++++ .../Components/Compo/Config/ProfileMan.razor | 5 +- .../Compo/Config/ProfileMan.razor.cs | 55 +++++++++++++++- Lux.UI/Lux.UI.csproj | 2 +- Resources/ChangeLog.html | 2 +- Resources/VersNum.txt | 2 +- Resources/manifest.xml | 2 +- 13 files changed, 231 insertions(+), 13 deletions(-) diff --git a/EgwCoreLib.Lux.Data/DataLayerContext.cs b/EgwCoreLib.Lux.Data/DataLayerContext.cs index afbb5d57..2b437595 100644 --- a/EgwCoreLib.Lux.Data/DataLayerContext.cs +++ b/EgwCoreLib.Lux.Data/DataLayerContext.cs @@ -8,7 +8,9 @@ using EgwCoreLib.Lux.Data.DbModel.Stock; using EgwCoreLib.Lux.Data.DbModel.Task; using EgwCoreLib.Lux.Data.DbModel.Utils; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.Extensions.Configuration; +using Newtonsoft.Json; using NLog; using System; using System.Collections.Generic; @@ -120,12 +122,29 @@ namespace EgwCoreLib.Lux.Data relationship.DeleteBehavior = DeleteBehavior.Restrict; } - // fig key relazioni Tags + // fix key relazioni Tags modelBuilder.Entity() .HasKey(jtt => new { jtt.JobID, jtt.CodTag }); modelBuilder.Entity() .HasKey(jtt => new { jtt.JobStepID, jtt.CodTag }); + // gestione deserializzazione smart x oggetti con liste implicite +#if false + modelBuilder.Entity() + .Property(e => e.TagsList) + .HasConversion( + v => JsonConvert.SerializeObject(v), // Da List a String (per il DB) + v => JsonConvert.DeserializeObject>(v) ?? new List(), // Da String a List (per C#) + new ValueComparer>( // Fondamentale per il tracking delle modifiche! + (c1, c2) => c1.SequenceEqual(c2), + c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())), + c => c.ToList())); +#endif + + modelBuilder.Entity() + .Property(e => e.TagsList) + .HasColumnType("json"); + #if false // JobTask ↔ Tags modelBuilder.Entity() diff --git a/EgwCoreLib.Lux.Data/DbModel/Production/ProductionAssignModel.cs b/EgwCoreLib.Lux.Data/DbModel/Production/ProductionAssignModel.cs index 085d7874..9f45cfaf 100644 --- a/EgwCoreLib.Lux.Data/DbModel/Production/ProductionAssignModel.cs +++ b/EgwCoreLib.Lux.Data/DbModel/Production/ProductionAssignModel.cs @@ -1,4 +1,6 @@ -using System; +using EgwCoreLib.Lux.Data.DbModel.Sales; +using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -28,9 +30,68 @@ namespace EgwCoreLib.Lux.Data.DbModel.Production /// public int OrderRowID { get; set; } = 0; + /// + /// Codice UID della riga ordine riferita + /// + public string OrderRowUID { get; set; } = "POR.00.00000000"; + /// /// Codice plant di assegnazione /// public string ProdPlantCod { get; set; } = ""; + + /// + /// Elenco assegnazioni con gestione serializzazione/deserializzazione inclusa + /// + public List TagsList { get; set; } = new(); + + /// + /// Num parts complessivamente incluse + /// + public int NumParts { get; set; } = 0; + + /// + /// Tempo stimato complessivo + /// + public int EstimTime { get; set; } = 0; + + /// + /// Navigazione OrderRow + /// + [ForeignKey("OrderRowID")] + public virtual OrderRowModel OrderRowNav { get; set; } = null!; + +#if false + /// + /// Assegnazione dei Tags di produzione come List da gestire serializzando/deserializzando + /// + public string RawAssign { get; set; } = ""; + + /// + /// Elenco assegnazioni con gestione serializzazione/deserializzazione inclusa + /// + [NotMapped] + public List TagsList + { + get + { + List result = new List(); + if (!string.IsNullOrEmpty(RawAssign) && RawAssign.Length > 2) + { + try + { + result = JsonConvert.DeserializeObject>(RawAssign) ?? new List(); + } + catch + { } + } + return result; + } + set + { + RawAssign = JsonConvert.SerializeObject(value); + } + } +#endif } } diff --git a/EgwCoreLib.Lux.Data/DbModel/Production/ProductionPlannerModel.cs b/EgwCoreLib.Lux.Data/DbModel/Production/ProductionPlannerModel.cs index 744ec695..f3447359 100644 --- a/EgwCoreLib.Lux.Data/DbModel/Production/ProductionPlannerModel.cs +++ b/EgwCoreLib.Lux.Data/DbModel/Production/ProductionPlannerModel.cs @@ -20,5 +20,20 @@ namespace EgwCoreLib.Lux.Data.DbModel.Production { [Key] public int ProdPlannerID { get; set; } + + /// + /// Elenco delle assegnazioni dei record ProdAssign incluse + /// + public List ListProdAssignID { get; set; } = new(); + + /// + /// Num parts complessivamente incluse + /// + public int NumParts { get; set; } = 0; + + /// + /// Tempo stimato complessivo + /// + public int EstimTime { get; set; } = 0; } } diff --git a/EgwCoreLib.Lux.Data/Services/ConfigDataService.cs b/EgwCoreLib.Lux.Data/Services/ConfigDataService.cs index 8d0ff993..832d4ae3 100644 --- a/EgwCoreLib.Lux.Data/Services/ConfigDataService.cs +++ b/EgwCoreLib.Lux.Data/Services/ConfigDataService.cs @@ -55,7 +55,26 @@ namespace EgwCoreLib.Lux.Data.Services { List result = new List(); // leggo obj da redis cache - var currKey = $"{redisBaseKey}:{execEnvironment}:PROFLIST:{ProfReq}"; + var currKey = $"{redisBaseKey}:{execEnvironment}:PROF:LIST:{ProfReq}"; + RedisValue rawData = redisDb.StringGet(currKey); + // prendo solo i valori validi (Name <> FamilyName) + if (rawData.HasValue) + { + var currList = JsonConvert.DeserializeObject>($"{rawData}"); + result = currList ?? new List(); + } + return result; + } + + /// + /// Restituisce l'elenco dei profili da cache REDIS + /// + /// + public List ProfileThreshList(Constants.EXECENVIRONMENTS execEnvironment, string ProfReq = "Default") + { + List result = new List(); + // leggo obj da redis cache + var currKey = $"{redisBaseKey}:{execEnvironment}:PROF:THRESH:{ProfReq}"; RedisValue rawData = redisDb.StringGet(currKey); // prendo solo i valori validi (Name <> FamilyName) if (rawData.HasValue) diff --git a/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs b/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs index 0bb1679c..694be58b 100644 --- a/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs +++ b/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs @@ -1759,11 +1759,11 @@ namespace EgwCoreLib.Lux.Data.Services } /// - /// Esegue salvataggio ProfileList sul DB + /// MockUp (fake) salvataggio ProfileList sul DB /// - /// UID dell'item offerta di cui si è ricevuto la BOM + /// UID ricezione (default tipicamente) /// Environment dell'item - /// HardwareModelList serializzata + /// ProfileList serializzata /// public async Task SaveProfileListAsync(string uID, Constants.EXECENVIRONMENTS execEnvironment, string rawContent) { @@ -1779,6 +1779,27 @@ namespace EgwCoreLib.Lux.Data.Services } } + /// + /// MockUp (fake) salvataggio ProfileThreshold sul DB + /// + /// UID del profilo + /// Environment dell'item + /// ThresholdList serializzata + /// + public async Task SaveProfileThreshAsync(string uID, Constants.EXECENVIRONMENTS execEnvironment, string rawContent) + { + // 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 { } + } + } + /// /// Restituisce elenco SellingItem dato envir /// diff --git a/EgwCoreLib.Lux.Data/Services/ImageCacheService.cs b/EgwCoreLib.Lux.Data/Services/ImageCacheService.cs index 5ce89cb4..df1c395f 100644 --- a/EgwCoreLib.Lux.Data/Services/ImageCacheService.cs +++ b/EgwCoreLib.Lux.Data/Services/ImageCacheService.cs @@ -412,13 +412,28 @@ namespace EgwCoreLib.Lux.Data.Services public async Task SaveProfileListAsync(string uid, Constants.EXECENVIRONMENTS env, string rawData) { // salvo img in cache - string currKey = $"{redisBaseKey}:{env}:PROFLIST:{uid.Replace("/", ":")}"; + string currKey = $"{redisBaseKey}:{env}:PROF:LIST:{uid.Replace("/", ":")}"; var done = await _redisService.SetAsync(currKey, rawData); // invio notifica nuova svg generata sul canale... viene inviato solo svg con ID nel canale string notifyChannel = $"{chProfList}:{uid}"; long numSent = await _redisService.PublishAsync(notifyChannel, rawData); return done; } + /// + /// Salva e invia su channel profile threshold x profilo gestiti + /// + /// + /// + public async Task SaveProfileThreshAsync(string uid, Constants.EXECENVIRONMENTS env, string rawData) + { + // salvo img in cache + string currKey = $"{redisBaseKey}:{env}:PROF:THRESH:{uid.Replace("/", ":")}"; + var done = await _redisService.SetAsync(currKey, rawData); + // invio notifica nuova svg generata sul canale... viene inviato solo svg con ID nel canale + string notifyChannel = $"{chProfThresh}:{uid}"; + long numSent = await _redisService.PublishAsync(notifyChannel, rawData); + return done; + } /// /// Salva e invia su channel shape per item (UID.GroupId) richiesto @@ -527,6 +542,7 @@ namespace EgwCoreLib.Lux.Data.Services private readonly string chHwOpt = "lux:hw:opt"; private readonly string chPng = "lux:png:img"; private readonly string chProfList = "lux:prof:list"; + private readonly string chProfThresh = "lux:prof:thresh"; private readonly string chShape = "shape:curr"; private readonly string chSvg = "lux:svg:img"; private readonly string chUpdate = "lux::update"; diff --git a/Lux.API/Services/ExternalMessageProcessor.cs b/Lux.API/Services/ExternalMessageProcessor.cs index b05cf947..cfae2fc1 100644 --- a/Lux.API/Services/ExternalMessageProcessor.cs +++ b/Lux.API/Services/ExternalMessageProcessor.cs @@ -214,6 +214,17 @@ namespace Lux.API.Services await dbService.SaveProfileListAsync(UID, retData.ExecEnvironment, profList); saved = true; } + + // gestione ritorno dati Threshold x profilo VALIDI per JWD + if (retData.Args.ContainsKey("ThresholdList")) + { + // recupero UID e elenco profili validi + string threshList = retData.Args["ThresholdList"]; + // salvo ProfileList ricevuta + await cacheService.SaveProfileThreshAsync(UID, retData.ExecEnvironment, threshList); + await dbService.SaveProfileThreshAsync(UID, retData.ExecEnvironment, threshList); + saved = true; + } } } return saved; diff --git a/Lux.UI/Components/Compo/Config/ProfileMan.razor b/Lux.UI/Components/Compo/Config/ProfileMan.razor index af861de3..1f56cf73 100644 --- a/Lux.UI/Components/Compo/Config/ProfileMan.razor +++ b/Lux.UI/Components/Compo/Config/ProfileMan.razor @@ -6,7 +6,10 @@
Conf. Profilo
- + +
+
+
diff --git a/Lux.UI/Components/Compo/Config/ProfileMan.razor.cs b/Lux.UI/Components/Compo/Config/ProfileMan.razor.cs index 6b99b6cf..55d88b7d 100644 --- a/Lux.UI/Components/Compo/Config/ProfileMan.razor.cs +++ b/Lux.UI/Components/Compo/Config/ProfileMan.razor.cs @@ -68,6 +68,17 @@ namespace Lux.UI.Components.Compo.Config await callRefreshProfList(); } + /// + /// Update soglie da elenco profili + /// + /// + + protected async Task DoReqUpdateThresh() + { + // chiamata richiesta update da calc + await callRefreshProfThresh(); + } + protected override void OnInitialized() { apiUrl = Config.GetValue("ServerConf:Prog.ApiUrl") ?? ""; @@ -144,7 +155,7 @@ namespace Lux.UI.Components.Compo.Config #region Private Methods /// - /// Effettua vera richiesta della BOM + /// Effettua vera richiesta elenco profili gestiti /// /// private async Task callRefreshProfList() @@ -174,6 +185,48 @@ namespace Lux.UI.Components.Compo.Config await CService.CallRestPost($"{apiUrl}/{genericBasePath}", $"{calcTag}/{reqUid}", req); } + private string cssBtnThresh + { + get => ListRecords != null && ListRecords.Count > 0 ? "btn-info" : "btn-secondary disabled"; + } + + /// + /// Effettua richiesta delle soglie dati i profili + /// + /// + private async Task callRefreshProfThresh() + { + Dictionary DictExec = new Dictionary(); + var cMode = Egw.Window.Data.Enums.QuestionModes.CONFIG; + var cSubMode = Egw.Window.Data.Enums.QuestionConfSubModes.THRESHOLDLIST; + DictExec.Add("UID", ""); + DictExec.Add("RUID", ""); + DictExec.Add("ProfileName", ""); + DictExec.Add("Mode", $"{(int)cMode}"); + DictExec.Add("SubMode", $"{(int)cSubMode}"); + // ciclo x tutti i profili... + foreach (var profile in ListRecords) + { + string reqUid = profile; + //DictExec.Add("UID", reqUid); + DictExec["UID"] = reqUid; + DictExec["ProfileName"] = reqUid; + // compongo righiesta + // creo registrazione richiesta... + var ruid = await CRService.AddRequestAsync($"{cEnvir}", $"{cMode}-{cSubMode}", reqUid); + // aggiungo RUID effettivo + DictExec["RUID"] = ruid; + //DictExec.Add("RUID", ruid); + CalcRequestDTO req = new CalcRequestDTO() + { + EnvType = cEnvir, + DictExec = DictExec + }; + // chiamo la chiamata POST alla API, che manda la richiesta via REDIS + await CService.CallRestPost($"{apiUrl}/{genericBasePath}", $"{calcTag}/{reqUid}", req); + } + } + private void FullUpdate() { ReloadData(); diff --git a/Lux.UI/Lux.UI.csproj b/Lux.UI/Lux.UI.csproj index a8e933a6..15a38085 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 - 0.9.2512.1912 + 0.9.2512.1916 diff --git a/Resources/ChangeLog.html b/Resources/ChangeLog.html index c55d27e2..8ac251db 100644 --- a/Resources/ChangeLog.html +++ b/Resources/ChangeLog.html @@ -1,6 +1,6 @@ LUX - Web Windows MES -

Versione: 0.9.2512.1912

+

Versione: 0.9.2512.1916


Note di rilascio:
  • diff --git a/Resources/VersNum.txt b/Resources/VersNum.txt index 72aae549..83b089ed 100644 --- a/Resources/VersNum.txt +++ b/Resources/VersNum.txt @@ -1 +1 @@ -0.9.2512.1912 +0.9.2512.1916 diff --git a/Resources/manifest.xml b/Resources/manifest.xml index 90385e7a..78573a14 100644 --- a/Resources/manifest.xml +++ b/Resources/manifest.xml @@ -1,6 +1,6 @@ - 0.9.2512.1912 + 0.9.2512.1916 http://nexus.steamware.net/repository/SWS/GPW/stable/GPW.UI.zip http://nexus.steamware.net/repository/SWS/GPW/stable/ChangeLog.html false