From 6d2d1603afbda769810c78b26d83811c182e6f2d Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Thu, 16 Apr 2026 08:17:34 +0200 Subject: [PATCH] Aggiunta metodo x snapshot quotdiani FluxLog --- MP.Core/Utils.cs | 3 + MP.Data/Controllers/MpIocController.cs | 106 +++++++++--- MP.IOC/Controllers/IOBController.cs | 161 ++++++------------ MP.IOC/Data/MpDataService.cs | 216 ++++++++++++++++++++++++- 4 files changed, 356 insertions(+), 130 deletions(-) diff --git a/MP.Core/Utils.cs b/MP.Core/Utils.cs index 53d2bd69..aa94c020 100644 --- a/MP.Core/Utils.cs +++ b/MP.Core/Utils.cs @@ -24,10 +24,13 @@ namespace MP.Core public const string redisDecNumArtKey = redisBaseAddr + "Cache:DecNumArt"; public const string redisDossByMac = redisBaseAddr + "Cache:DossByMac"; + public const string redisDossByMacLast = redisBaseAddr + "Cache:DossByMacLast"; public const string redisEventList = redisBaseAddr + "Cache:EventList"; public const string redisFluxByMac = redisBaseAddr + "Cache:FluxByMac"; + public const string redisFluxByMacFirst = redisBaseAddr + "Cache:FluxByMacFirst"; + public const string redisConfFlux = redisBaseAddr + "Cache:ConfFlux"; public const string redisFluxLogFilt = redisBaseAddr + "Cache:FluxLogFilt"; diff --git a/MP.Data/Controllers/MpIocController.cs b/MP.Data/Controllers/MpIocController.cs index 729bdceb..73a081d3 100644 --- a/MP.Data/Controllers/MpIocController.cs +++ b/MP.Data/Controllers/MpIocController.cs @@ -55,6 +55,7 @@ namespace MP.Data.Controllers } return fatto; } + /// /// Restituisce l'anagrafica STATI per intero /// @@ -73,21 +74,21 @@ namespace MP.Data.Controllers } /// - /// Elenco tabella decodifica articoli / codice decimale + /// Record ConfFlux dato macchina (oppure tutti se vuoto) /// - /// Vuoto = tutti / Singolo CodArt + /// /// - public async Task> DecNumArtGetFiltAsync(string codArt = "") + public async Task> ConfFluxFiltAsync(string idxMacc) { - List dbResult = new List(); - using (var dbCtx = new MoonProContext(_configuration)) + List dbResult = new(); + using (var dbCtx = new MoonPro_FluxContext(_configuration)) { - var query = dbCtx.DbSetDecNumArt + var query = dbCtx.DbSetConfFlux .AsNoTracking() .AsQueryable(); - if (!string.IsNullOrEmpty(codArt)) - query = query.Where(x => x.CodArticolo == codArt); + if (!string.IsNullOrEmpty(idxMacc)) + query = query.Where(x => x.IdxMacchina == idxMacc); dbResult = await query.ToListAsync(); } @@ -153,6 +154,7 @@ namespace MP.Data.Controllers } return dbResult; } + /// /// Intera tab dati macchina /// @@ -205,11 +207,54 @@ namespace MP.Data.Controllers return fatto; } + /// + /// Elenco tabella decodifica articoli / codice decimale + /// + /// Vuoto = tutti / Singolo CodArt + /// + public async Task> DecNumArtGetFiltAsync(string codArt = "") + { + List dbResult = new List(); + using (var dbCtx = new MoonProContext(_configuration)) + { + var query = dbCtx.DbSetDecNumArt + .AsNoTracking() + .AsQueryable(); + + if (!string.IsNullOrEmpty(codArt)) + query = query.Where(x => x.CodArticolo == codArt); + + dbResult = await query.ToListAsync(); + } + return dbResult; + } + public void Dispose() { _configuration = null; } + /// + /// Stored x recuperare ultimi dossier macchina + /// + /// + /// + public async Task> DossGetLastByMaccAsync(string idxMacc) + { + List dbResult = new(); + using (var dbCtx = new MoonPro_FluxContext(_configuration)) + { + var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacc); + + dbResult = await dbCtx + .DbSetDossiers + .FromSqlRaw("exec dbo.stp_DOSS_getLastByMacch @idxMacchina", IdxMacchina) + .AsNoTracking() + .ToListAsync(); + } + return dbResult; + } + /// /// Aggiunta record EventList /// @@ -260,6 +305,29 @@ namespace MP.Data.Controllers return fatto; } + /// + /// Chiamata x stored recupero FluxLog x macchina (first) + /// + /// + /// + /// + public async Task> FluxLogFirstByMaccAsync(string idxMacc, int numMax) + { + List dbResult = new(); + using (var dbCtx = new MoonPro_FluxContext(_configuration)) + { + var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacc); + var NumMax = new SqlParameter("@numMax", numMax); + + dbResult = await dbCtx + .DbSetFluxLog + .FromSqlRaw("exec dbo.stp_FL_getFirstByMacc @IdxMacchina, @numMax", IdxMacchina, NumMax) + .AsNoTracking() + .ToListAsync(); + } + return dbResult; + } + /// /// Elenco ultimi n record flux log dato macchina e flusso (ordinato x data registrazione) /// @@ -336,25 +404,25 @@ namespace MP.Data.Controllers } /// - /// Record ConfFlux dato macchina (oppure tutti se vuoto) + /// Stored x eseguire Snapshot FluxLog (= Dossier) dato periodo /// /// /// - public async Task> ConfFluxFiltAsync(string idxMacc) + public async Task FluxLogTakeSnapshotLastAsync(string idxMacc, DateTime dataInizio, DateTime dataFine) { - List dbResult = new(); + bool fatto = false; using (var dbCtx = new MoonPro_FluxContext(_configuration)) { - var query = dbCtx.DbSetConfFlux - .AsNoTracking() - .AsQueryable(); + var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacc); + var DataInizio = new SqlParameter("@DtMin", dataInizio); + var DataFine = new SqlParameter("@DtMax", dataFine); - if (!string.IsNullOrEmpty(idxMacc)) - query = query.Where(x => x.IdxMacchina == idxMacc); - - dbResult = await query.ToListAsync(); + var result = await dbCtx + .Database + .ExecuteSqlRawAsync("EXEC stp_FL_TakeSnapshotLast @IdxMacchina, @DtMin, @DtMax", IdxMacchina, DataInizio, DataFine); + fatto = result > 0; } - return dbResult; + return fatto; } public bool KeepAliveUpsert(string IdxMacc, DateTime OraServer, DateTime OraMacc) diff --git a/MP.IOC/Controllers/IOBController.cs b/MP.IOC/Controllers/IOBController.cs index 4f523be7..f283a8d7 100644 --- a/MP.IOC/Controllers/IOBController.cs +++ b/MP.IOC/Controllers/IOBController.cs @@ -103,7 +103,6 @@ namespace MP.IOC.Controllers } } - /// /// Processa una chiamata POST per l'invio di un array Json di oggetti input (EVENTI) /// POST: IOB/evListJson/SIMUL_03 @@ -136,7 +135,6 @@ namespace MP.IOC.Controllers return Ok(answ); } -#if false /// /// Sistema Dossier/Snapshot giornalieri x impianto indicato, andando a generare 1 Dossier /// giornaliero x ogni giornata dall'ultimo registrato alla data corrente @@ -144,80 +142,25 @@ namespace MP.IOC.Controllers /// /// /// - public string fixDailyDossier(string id) + [HttpGet("fixDailyDossier/{id}")] + public async Task FixDailyDossier(string id) { - string answ = ""; - // attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il - // carattere "|" che poi trasformiamo ora in "#" + if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); + // Multi: gestione carattere "|" trasformato in "#" id = id.Replace("|", "#"); - // effettuo processing + + string answ = ""; try { - DataLayer DataLayerObj = new DataLayer(); - // verifico se si possa processare, ovvero tab ConfFlux x macchina sia valorizzata... - var confDataMach = DataLayerObj.confFluxMach(id); - if (confDataMach.Count > 0) - { - // determino ultima data da processare (inizio oggi, a mezzanotte) - DateTime dtTo = DateTime.Today; - DateTime dtFrom = dtTo; - // determino data di partenza, prima da dossier esistenti - var listaDoss = DataLayerObj.dossierLastByMach(id); - if (listaDoss.Count > 0) - { - // primo giorno DOPO ultima registrazione - dtFrom = listaDoss.OrderByDescending(x => x).FirstOrDefault().AddDays(1); - } - else - { - // ...o da fluxLog acquisiti... - var listaFL = DataLayerObj.fluxLogFirstByMach(id); - if (listaFL.Count > 0) - { - // giorno successivo a prima registrazione - dtFrom = listaFL.OrderBy(x => x).FirstOrDefault().AddDays(1); - } - } - string caller = $"takeFlogSnapshot({id})"; - DateTime dtStart = dtFrom.Date; - DateTime dtEnd = dtFrom; - // max 10 dossier alla volta (se non configurato diversamente) - int maxAdd = memLayer.ML.CRI("IO_numDossMaxCreate"); - if (dtStart < dtTo) - { - // verifico di avere almeno 1 dossier da produrre ciclo fino ad esaurire le - // date da processare - while (dtStart < dtTo && maxAdd > 0) - { - // sistemo end - dtEnd = dtStart.AddDays(1); - // effettuo chiamata registrazione snapshot! - answ = doSaveFLSnapshot(id, dtStart, dtEnd, caller); - // incremento START... - dtStart = dtEnd; - // riduco il numero di chiamate ammesse x singolo task - maxAdd--; - } - // reset cache dossier... - DataLayerObj.dossierLastByMachReset(id); - } - else - { - answ = "NO more to add"; - } - } - else - { - answ = "NO ConfFluxData"; - } + answ = await DService.FixDailyDossierAsync(id); } catch (Exception exc) { - logger.lg.scriviLog($"Eccezione in recupero fixDailyDossier{Environment.NewLine}{exc}", tipoLog.EXCEPTION); + Log.Error($"Errore in FixDailyDossier{Environment.NewLine}{exc}"); + return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } - return answ; - } -#endif + return Ok(answ); + } /// /// Sistema ODL giornalieri x impianto indicato, andando a generare 1 ODL giornaliero x ogni @@ -1237,6 +1180,47 @@ namespace MP.IOC.Controllers #region Private Methods + /// + /// Processing effettivo EvListJson + /// + /// + /// + /// + private async Task processEvListJsonAsync(string idxMacc, string content) + { + string answ = ""; + int insDone = 0; + + // procedo a deserializzare in blocco l'oggetto... + EvJsonPayloadDto receivedData = JsonConvert.DeserializeObject(content) ?? new(); + + // se ho qualcosa da processare... + if (receivedData != null) + { + // per ogni valore --> processo! + try + { + foreach (var item in receivedData.eventList) + { + // formato datetime come yyyyMMddHHmmssfff -->es: 20181223180600000 + answ = await DService.ProcessInputAsync(idxMacc, item.valore, item.dtEve.ToString("yyyyMMddHHmmssfff"), item.dtCurr.ToString("yyyyMMddHHmmssfff"), item.cnt.ToString()); + insDone++; + } + // se vuoto --> OK! + if (string.IsNullOrEmpty(answ)) + { + answ = $"OK {insDone} processed"; + } + } + catch (Exception exc) + { + Log.Error($"Errore in fase invio valori inputJson{Environment.NewLine}{exc}"); + answ = "NO"; + } + } + return answ; + } + /// /// Effettivo processing FLogJson /// @@ -1349,47 +1333,6 @@ namespace MP.IOC.Controllers return answ; } - /// - /// Processing effettivo EvListJson - /// - /// - /// - /// - private async Task processEvListJsonAsync(string idxMacc, string content) - { - string answ = ""; - int insDone = 0; - - // procedo a deserializzare in blocco l'oggetto... - EvJsonPayloadDto receivedData = JsonConvert.DeserializeObject(content) ?? new(); - - // se ho qualcosa da processare... - if (receivedData != null) - { - // per ogni valore --> processo! - try - { - foreach (var item in receivedData.eventList) - { - // formato datetime come yyyyMMddHHmmssfff -->es: 20181223180600000 - answ = await DService.ProcessInputAsync(idxMacc, item.valore, item.dtEve.ToString("yyyyMMddHHmmssfff"), item.dtCurr.ToString("yyyyMMddHHmmssfff"), item.cnt.ToString()); - insDone++; - } - // se vuoto --> OK! - if (string.IsNullOrEmpty(answ)) - { - answ = $"OK {insDone} processed"; - } - } - catch (Exception exc) - { - Log.Error($"Errore in fase invio valori inputJson{Environment.NewLine}{exc}"); - answ = "NO"; - } - } - return answ; - } - /// /// Effettua processing UserLog /// diff --git a/MP.IOC/Data/MpDataService.cs b/MP.IOC/Data/MpDataService.cs index aa67aa96..9de837b8 100644 --- a/MP.IOC/Data/MpDataService.cs +++ b/MP.IOC/Data/MpDataService.cs @@ -946,6 +946,80 @@ namespace MP.IOC.Data return fatto; } + /// + /// Task completo sistemazione dossier quotidiani mancanti + /// + /// + /// + public async Task FixDailyDossierAsync(string idxMacc) + { + string answ = ""; + // verifico se si possa processare, ovvero tab ConfFlux x macchina sia valorizzata... + var confDataMach = await ConfFluxMach(idxMacc); + if (confDataMach.Count > 0) + { + // determino ultima data da processare (inizio oggi, a mezzanotte) + DateTime dtTo = DateTime.Today; + DateTime dtFrom = dtTo; + // determino data di partenza, prima da dossier esistenti + var listaDoss = await DossierLastByMachAsync(idxMacc); + if (listaDoss.Count > 0) + { + // primo giorno DOPO ultima registrazione + dtFrom = listaDoss.OrderByDescending(x => x).FirstOrDefault().AddDays(1); + } + else + { + // ...o da fluxLog acquisiti... + var listaFL = await FluxLogFirstByMachAsync(idxMacc); + if (listaFL.Count > 0) + { + // giorno successivo a prima registrazione + dtFrom = listaFL.OrderBy(x => x).FirstOrDefault().AddDays(1); + } + } + string caller = $"takeFlogSnapshot({idxMacc})"; + DateTime dtStart = dtFrom.Date; + DateTime dtEnd = dtFrom; + // max 10 dossier alla volta (se non configurato diversamente) + int maxAdd = 1; + string confVal = await tryGetConfig("IO_numDossMaxCreate"); + if (!string.IsNullOrEmpty(confVal)) + { + int.TryParse(confVal, out maxAdd); + } + + if (dtStart < dtTo) + { + // verifico di avere almeno 1 dossier da produrre ciclo fino ad esaurire le + // date da processare + while (dtStart < dtTo && maxAdd > 0) + { + // sistemo end + dtEnd = dtStart.AddDays(1); + // effettuo chiamata registrazione snapshot! + answ = await FluxLogSaveSnapshotAsync(idxMacc, dtStart, dtEnd, caller); + // incremento START... + dtStart = dtEnd; + // riduco il numero di chiamate ammesse x singolo task + maxAdd--; + } + // reset cache dossier... + await DossierLastByMachResetAsync(idxMacc); + answ = "OK"; + } + else + { + Log.Warn("FixDailyDossierAsync | NO more to add"); + } + } + else + { + Log.Warn("FixDailyDossierAsync | NO ConfFluxData"); + } + return answ; + } + public async Task FlushRedisCache() { await Task.Delay(1); @@ -1209,7 +1283,7 @@ namespace MP.IOC.Data /// /// - /// id odl da cercare + /// idxMacc odl da cercare /// public async Task> ListGiacenze(int IdxOdl) { @@ -1385,7 +1459,7 @@ namespace MP.IOC.Data } /// - /// Elenco id Macchine che abbiano dati FLuxLog, nel periodo indicato + /// Elenco idxMacc Macchine che abbiano dati FLuxLog, nel periodo indicato /// /// /// @@ -3880,6 +3954,144 @@ namespace MP.IOC.Data } } + /// + /// Restituisce l'elenco codici flusso (da confFlux) x una macchina (se presenti) Impiegata + /// anche cache redis + /// + /// + /// + private async Task> ConfFluxMach(string idxMacchina) + { + List resultList = new List(); + string tag = string.IsNullOrEmpty(idxMacchina) ? "ALL" : idxMacchina; + var currKey = $"{Utils.redisConfFlux}:{tag}"; + RedisValue rawData = await redisDb.StringGetAsync(currKey); + if (rawData.HasValue) + { + resultList = JsonConvert.DeserializeObject>($"{rawData}") ?? new(); + } + else + { + var dbData = await IocDbController.ConfFluxFiltAsync(idxMacchina); + resultList = dbData + .Select(x => x.CodFlux) + .ToList(); + // serializzo e salvo... + rawData = JsonConvert.SerializeObject(resultList); + await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache)); + } + if (resultList == null) + { + resultList = new(); + } + return resultList; + } + + /// + /// Restituisce l'elenco delle date dei dossier x una macchina (se presenti) Impiegata anche + /// cache redis + /// + /// + /// + private async Task> DossierLastByMachAsync(string idxMacchina) + { + List resultList = new List(); + + var currKey = $"{Utils.redisDossByMacLast}:{idxMacchina}"; + RedisValue rawData = await redisDb.StringGetAsync(currKey); + if (rawData.HasValue) + { + resultList = JsonConvert.DeserializeObject>($"{rawData}") ?? new(); + } + else + { + var dbData = await IocDbController.DossGetLastByMaccAsync(idxMacchina); + resultList = dbData + .Select(x => x.DtRif) + .ToList(); + // serializzo e salvo... + rawData = JsonConvert.SerializeObject(resultList); + await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache)); + } + if (resultList == null) + { + resultList = new List(); + } + return resultList; + } + + /// + /// Svuota la cache redis x l'elenco delle righe di confFlux x una macchina (se presenti) + /// + /// + /// + private async Task DossierLastByMachResetAsync(string idxMacchina) + { + bool answ = false; + var currKey = $"{Utils.redisDossByMacLast}:{idxMacchina}"; + await redisDb.KeyDeleteAsync(currKey); + return answ; + } + + /// + /// Restituisce l'elenco delle data-ora di confFlux x una macchina (se presenti) Impiegata + /// anche cache redis + /// + /// + /// num record da recuperare + /// + private async Task> FluxLogFirstByMachAsync(string idxMacchina, int numMax = 10) + { + List resultList = new List(); + + var currKey = $"{Utils.redisFluxByMacFirst}:{idxMacchina}"; + RedisValue rawData = await redisDb.StringGetAsync(currKey); + if (rawData.HasValue) + { + resultList = JsonConvert.DeserializeObject>($"{rawData}") ?? new(); + } + else + { + var dbData = await IocDbController.FluxLogFirstByMaccAsync(idxMacchina, numMax); + resultList = dbData + .Select(x => x.dtEvento) + .ToList(); + // serializzo e salvo... + rawData = JsonConvert.SerializeObject(resultList); + await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache)); + } + if (resultList == null) + { + resultList = new List(); + } + return resultList; + } + + /// + /// Effettua vera chiamata x salvataggio snapshot dati FluxLog + /// + /// + /// + /// + /// + private async Task FluxLogSaveSnapshotAsync(string id, DateTime dtStart, DateTime dtEnd, string caller) + { + string answ = ""; + DateTime dataOraEvento = DateTime.Now; + Log.Debug($"{caller} | Richiesta snapshot dati FluxLog macchina: id: {id} | periodo: {dtStart} - {dtEnd}"); + try + { + bool fatto = await IocDbController.FluxLogTakeSnapshotLastAsync(id, dtStart, dtEnd); + answ = fatto ? "OK" : "KO"; + } + catch (Exception exc) + { + Log.Error($"Errore in {caller}{Environment.NewLine}{exc}"); + answ = "NO"; + } + return answ; + } + /// /// Recupero info ODL corrente da dati prod macchina ///