diff --git a/MP.Core/DTO/EvJsonPayloadDto.cs b/MP.Core/DTO/EvJsonPayloadDto.cs new file mode 100644 index 00000000..a4d7e8fd --- /dev/null +++ b/MP.Core/DTO/EvJsonPayloadDto.cs @@ -0,0 +1,11 @@ +namespace MP.Core.DTO +{ + public class EvJsonPayloadDto + { + #region Public Properties + + public List eventList { get; set; } = new(); + + #endregion Public Properties + } +} diff --git a/MP.Core/Utils.cs b/MP.Core/Utils.cs index 82b63f8d..aa94c020 100644 --- a/MP.Core/Utils.cs +++ b/MP.Core/Utils.cs @@ -11,6 +11,7 @@ namespace MP.Core public const string redisAKVKey = redisBaseAddr + "Cache:AKV"; public const string redisAnagGruppi = redisBaseAddr + "Cache:AnagGruppi"; + public const string redisAnagStati = redisBaseAddr + "Cache:AnagStati"; public const string redisArtByDossier = redisBaseAddr + "Cache:ArtByDossier"; @@ -20,11 +21,16 @@ namespace MP.Core public const string redisConfKey = redisBaseAddr + "Cache:Config"; + 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"; @@ -216,21 +222,22 @@ namespace MP.Core /// /// Chiave override per i valori in caso di dati che accedono al dominio dati di un altra app (es: baseAddr x IO legacy) /// - public static RedisKey RedKeyIobMemMap(string idxMacchina, string baseAddr = null) + public static RedisKey RedKeyIobConfYaml(string idxMacchina, string baseAddr = null) { var prefix = (baseAddr ?? redisBaseAddr).TrimEnd(':'); - return (RedisKey)$"{prefix}:MemMap:{idxMacchina}"; + return (RedisKey)$"{prefix}:IOB:{idxMacchina}:ConfYaml"; } + /// /// Hash dati MemMap di un IOB /// /// /// Chiave override per i valori in caso di dati che accedono al dominio dati di un altra app (es: baseAddr x IO legacy) /// - public static RedisKey RedKeyIobConfYaml(string idxMacchina, string baseAddr = null) + public static RedisKey RedKeyIobMemMap(string idxMacchina, string baseAddr = null) { var prefix = (baseAddr ?? redisBaseAddr).TrimEnd(':'); - return (RedisKey)$"{prefix}:IOB:{idxMacchina}:ConfYaml"; + return (RedisKey)$"{prefix}:MemMap:{idxMacchina}"; } /// diff --git a/MP.Data/Controllers/MpIocController.cs b/MP.Data/Controllers/MpIocController.cs index c1e8d1ca..41483f33 100644 --- a/MP.Data/Controllers/MpIocController.cs +++ b/MP.Data/Controllers/MpIocController.cs @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using MP.Data.DbModels; +using MP.Data.DbModels.Anag; using NLog; using System; using System.Collections.Generic; @@ -55,6 +56,45 @@ namespace MP.Data.Controllers return fatto; } + /// + /// Restituisce l'anagrafica STATI per intero + /// + /// + public async Task> AnagStatiGetAllAsync() + { + List dbResult = new List(); + using (var dbCtx = new MoonProContext(_configuration)) + { + dbResult = await dbCtx + .DbSetAnagStati + .AsNoTracking() + .ToListAsync(); + } + return dbResult; + } + + /// + /// Record ConfFlux dato macchina (oppure tutti se vuoto) + /// + /// + /// + public async Task> ConfFluxFiltAsync(string idxMacc) + { + List dbResult = new(); + using (var dbCtx = new MoonPro_FluxContext(_configuration)) + { + var query = dbCtx.DbSetConfFlux + .AsNoTracking() + .AsQueryable(); + + if (!string.IsNullOrEmpty(idxMacc)) + query = query.Where(x => x.IdxMacchina == idxMacc); + + dbResult = await query.ToListAsync(); + } + return dbResult; + } + /// /// Elenco da tabella Config /// @@ -65,10 +105,10 @@ namespace MP.Data.Controllers using (var dbCtx = new MoonProContext(_configuration)) { dbResult = dbCtx - .DbSetConfig - .AsNoTracking() - .OrderBy(x => x.Chiave) - .ToList(); + .DbSetConfig + .AsNoTracking() + .OrderBy(x => x.Chiave) + .ToList(); } return dbResult; } @@ -115,6 +155,24 @@ namespace MP.Data.Controllers return dbResult; } + /// + /// Intera tab dati macchina + /// + /// + public async Task> DatiMacchineGetAllAsync() + { + List dbResult = new List(); + using (var dbCtx = new MoonProContext(_configuration)) + { + dbResult = await dbCtx + .DbSetDatiMacchine + .AsNoTracking() + .OrderBy(x => x.IdxMacchina) + .ToListAsync(); + } + return dbResult; + } + /// /// Inserimento record in DDB /// @@ -149,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 /// @@ -204,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) /// @@ -279,6 +403,28 @@ namespace MP.Data.Controllers return fatto; } + /// + /// Stored x eseguire Snapshot FluxLog (= Dossier) dato periodo + /// + /// + /// + public async Task FluxLogTakeSnapshotLastAsync(string idxMacc, DateTime dataInizio, DateTime dataFine) + { + bool fatto = false; + using (var dbCtx = new MoonPro_FluxContext(_configuration)) + { + var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacc); + var DataInizio = new SqlParameter("@DtMin", dataInizio); + var DataFine = new SqlParameter("@DtMax", dataFine); + + var result = await dbCtx + .Database + .ExecuteSqlRawAsync("EXEC stp_FL_TakeSnapshotLast @IdxMacchina, @DtMin, @DtMax", IdxMacchina, DataInizio, DataFine); + fatto = result > 0; + } + return fatto; + } + public bool KeepAliveUpsert(string IdxMacc, DateTime OraServer, DateTime OraMacc) { bool fatto = false; @@ -379,6 +525,24 @@ namespace MP.Data.Controllers return dbResult; } + /// + /// Intera tabella relazione master/slave in machine (gestione setup master --> slave) + /// + /// + public async Task> Macchine2SlaveAsync() + { + List dbResult = new List(); + using (var dbCtx = new MoonProContext(_configuration)) + { + dbResult = await dbCtx + .DbSetM2S + .AsNoTracking() + .OrderBy(x => x.IdxMacchina) + .ToListAsync(); + } + return dbResult; + } + /// /// Elenco Record Macchine /// @@ -589,18 +753,18 @@ namespace MP.Data.Controllers /// Elenco da tabella MappaStatoExplModel /// /// - public List MseGetAll(int maxAge = 2000) + public async Task> MseGetAllAsync(int maxAge = 2000) { List dbResult = new List(); using (var dbCtx = new MoonProContext(_configuration)) { var maxAgeSec = new SqlParameter("@maxAgeSec", maxAge); - dbResult = dbCtx - .DbSetMSE - .FromSqlRaw("EXEC stp_MSE_getData @maxAgeSec", maxAgeSec) - .AsNoTracking() - .ToList(); + dbResult = await dbCtx + .DbSetMSE + .FromSqlRaw("EXEC stp_MSE_getData @maxAgeSec", maxAgeSec) + .AsNoTracking() + .ToListAsync(); } return dbResult; } @@ -1273,6 +1437,27 @@ namespace MP.Data.Controllers return dbResult; } + /// + /// Vista v_MSFD x singola macchina (da stored) - singolo record + /// + /// + /// + public async Task> VMSFDGetByMaccAsync(string idxMacc) + { + List dbResult = new List(); + using (var dbCtx = new MoonProContext(_configuration)) + { + var IdxMacchina = new SqlParameter("@pIdxMacchina", idxMacc); + + dbResult = await dbCtx + .DbSetMSFD + .FromSqlRaw("exec dbo.stp_MSFD_getMacc @pIdxMacchina", IdxMacchina) + .AsNoTracking() + .ToListAsync(); + } + return dbResult; + } + /// /// Vista v_MSFD delle machine MULTI filtrato x macchina (da stored) /// diff --git a/MP.Data/DbModels/Anag/DecNumArticoliModel.cs b/MP.Data/DbModels/Anag/DecNumArticoliModel.cs new file mode 100644 index 00000000..f2d3d8fa --- /dev/null +++ b/MP.Data/DbModels/Anag/DecNumArticoliModel.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace MP.Data.DbModels.Anag +{ + [Table("AlarmLog")] + public class DecNumArticoliModel + { + [Key] + public string CodArticolo { get; set; } = ""; + public int NumART { get; set; } = 0; + } +} diff --git a/MP.Data/DbModels/ConfFluxModel.cs b/MP.Data/DbModels/ConfFluxModel.cs new file mode 100644 index 00000000..68495241 --- /dev/null +++ b/MP.Data/DbModels/ConfFluxModel.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + + +#nullable disable +// +// This is here so CodeMaid doesn't reorganize this document +// +namespace MP.Data.DbModels +{ + [Table("ConfFlux")] + public partial class ConfFluxModel + { + #region Public Properties + + [MaxLength(50)] + public string IdxMacchina { get; set; } + + [MaxLength(50)] + public string CodFlux { get; set; } + + public bool EnabDoss { get; set; } + + #endregion Public Properties + } +} \ No newline at end of file diff --git a/MP.Data/MoonProContext.cs b/MP.Data/MoonProContext.cs index 86a3db1c..25ffff79 100644 --- a/MP.Data/MoonProContext.cs +++ b/MP.Data/MoonProContext.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using MP.Data.DbModels; +using MP.Data.DbModels.Anag; using NLog; #nullable disable @@ -45,6 +46,8 @@ namespace MP.Data public virtual DbSet DbSetAnagStati { get; set; } public virtual DbSet DbSetAnagTags { get; set; } public virtual DbSet DbSetArticoli { get; set; } + public virtual DbSet DbSetDecNumArt { get; set; } + public virtual DbSet DbSetConfig { get; set; } public virtual DbSet DbSetElConfProd { get; set; } public virtual DbSet DbSetLinkMenu { get; set; } diff --git a/MP.Data/MoonPro_FluxContext.cs b/MP.Data/MoonPro_FluxContext.cs index f68e84eb..bf060309 100644 --- a/MP.Data/MoonPro_FluxContext.cs +++ b/MP.Data/MoonPro_FluxContext.cs @@ -1,11 +1,9 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using MP.Core.DTO; using MP.Data.DbModels; -using MP.Data.DTO; using NLog; +using System; #nullable disable // @@ -54,6 +52,8 @@ namespace MP.Data public virtual DbSet DbSetFluxLog { get; set; } public virtual DbSet DbSetDossiers { get; set; } public virtual DbSet DbSetParetoFluxLog { get; set; } + public virtual DbSet DbSetConfFlux { get; set; } + #endregion Public Properties diff --git a/MP.Data/Services/StatusData.cs b/MP.Data/Services/StatusData.cs index 7c86ac9c..02b0b848 100644 --- a/MP.Data/Services/StatusData.cs +++ b/MP.Data/Services/StatusData.cs @@ -320,6 +320,10 @@ namespace MP.Data.Services return answ; } + /// + /// Elenco da tabella MappaStatoExplModel + /// + /// public async Task> MseGetAll(bool forceDb = false) { Stopwatch sw = new Stopwatch(); @@ -327,10 +331,10 @@ namespace MP.Data.Services sw.Start(); List? result = new List(); // cerco in _redisConn... - RedisValue rawData = redisDb.StringGet(Constants.redisMseKey); + RedisValue rawData = await redisDb.StringGetAsync(Constants.redisMseKey); if (rawData.HasValue && !forceDb) { - result = JsonConvert.DeserializeObject>($"{rawData}"); + result = JsonConvert.DeserializeObject>($"{rawData}") ?? new(); source = "REDIS"; } else diff --git a/MP.IOC/Controllers/IOBController.cs b/MP.IOC/Controllers/IOBController.cs index af325bda..5333055f 100644 --- a/MP.IOC/Controllers/IOBController.cs +++ b/MP.IOC/Controllers/IOBController.cs @@ -32,7 +32,7 @@ namespace MP.IOC.Controllers [HttpGet("addOptPar/{id}")] public async Task AddOptPar(string id, string pName, string pValue) { - DService.ScriviKeepAlive(id, DateTime.Now); + await DService.ScriviKeepAliveAsync(id, DateTime.Now); try { DService.AddOptPar4Machine(id, pName, pValue); @@ -88,21 +88,85 @@ namespace MP.IOC.Controllers /// /// [HttpGet("enabled/{id}")] - public IActionResult Enabled(string id) + public async Task Enabled(string id) { if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); - if (DService.IobInsEnab(id)) + try { - return Ok("OK"); + // Il metodo ora restituisce direttamente il booleano logico + bool isEnabled = await DService.IobInsEnabAsync(id); + + return isEnabled + ? Ok("OK") + : UnprocessableEntity("NO"); } - else + catch (Exception ex) { - //return StatusCode(503, "NO"); - return UnprocessableEntity("NO"); + Log.Error(ex, "Errore durante la verifica abilitazione per {Id}", id); + return StatusCode(500, "Errore interno del server"); } } + /// + /// Processa una chiamata POST per l'invio di un array Json di oggetti input (EVENTI) + /// POST: IOB/evListJson/SIMUL_03 + /// + /// ID dell'IOB + /// + [HttpPost("evListJson/{id}")] + public async Task EvListJson(string id, [FromBody] string content = "") + { + if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); + string answ = "-"; + try + { + // se ho dati... + if (content != "") + { + answ = await processEvListJsonAsync(id, content); + } + else + { + Log.Error($"Errore in EvListJson - no content"); + return StatusCode(StatusCodes.Status500InternalServerError, "NO"); + } + } + catch (Exception exc) + { + Log.Error($"Errore in EvListJson{Environment.NewLine}{exc}"); + return StatusCode(StatusCodes.Status500InternalServerError, "NO"); + } + return Ok(answ); + } + + /// + /// Sistema Dossier/Snapshot giornalieri x impianto indicato, andando a generare 1 Dossier + /// giornaliero x ogni giornata dall'ultimo registrato alla data corrente + /// es: http://url_site/MP/IO/IOB/fixDailyDossier/SIMUL_03 + /// + /// + /// + [HttpGet("fixDailyDossier/{id}")] + public async Task FixDailyDossier(string id) + { + if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); + // Multi: gestione carattere "|" trasformato in "#" + id = id.Replace("|", "#"); + + string answ = ""; + try + { + answ = await DService.FixDailyDossierAsync(id); + } + catch (Exception exc) + { + Log.Error($"Errore in FixDailyDossier{Environment.NewLine}{exc}"); + return StatusCode(StatusCodes.Status500InternalServerError, "NO"); + } + return Ok(answ); + } + /// /// Sistema ODL giornalieri x impianto indicato, andando a generare 1 ODL giornaliero x ogni /// giornata dall'ultimo ODL aperto alla data corrente @@ -262,6 +326,36 @@ namespace MP.IOC.Controllers } } + /// + /// Recupera ArtNum dato CodXdl (per impianti che accettano solo INT in scrittura): + /// GET: IOB/getArtNum/SIMUL_03?CodXdl=ABC123 + /// + /// IdxMacchina (NON considerato) + /// CodXdl richiesto, se vuoto restituisce TUTTI i valori in tabella di decodifica + /// Json contenente le righe delle codifiche attive Articolo/Numero + [HttpGet("getArtNum/{id}")] + public async Task GetArtNum(string id, string CodArt = "") + { + // in realtà ID macchina non conterebbe... + if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); + // Multi: gestione carattere "|" trasformato in "#" + id = id.Replace("|", "#"); + string answ = ""; + try + { + await DService.ScriviKeepAliveAsync(id, DateTime.Now); + // leggo da REDIS eventuale elenco task x macchina... + Dictionary valori = await DService.GetArtNumAsync(CodArt); + answ = JsonConvert.SerializeObject(valori); + } + catch (Exception exc) + { + Log.Error($"Errore in GetArtNum{Environment.NewLine}{exc}"); + return StatusCode(StatusCodes.Status500InternalServerError, "NO"); + } + return Ok(answ); + } + /// /// Recupera COUNTER x macchina: /// GET: IOB/getCounter/SIMUL_03 @@ -425,6 +519,51 @@ namespace MP.IOC.Controllers return Ok(answ.ToString("yyyy-MM-dd HH:mm:ss")); } + /// + /// Restituisce il valore dello stato di IDLE della macchina, quindi SOLO SE NON é in lavoro + /// e già convertito in minuti... + /// GET: IOB/getIdlePeriod/SIMUL_01 + /// + /// + /// + [HttpGet("getIdlePeriod/{id}")] + public async Task GetIdlePeriod(string id) + { + if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID"); + // Multi: gestione carattere "|" trasformato in "#" + id = id.Replace("|", "#"); + int answ = 0; + + // chiamo metodo x avere stato macchina... + try + { + await DService.ScriviKeepAliveAsync(id, DateTime.Now); + var mseData = await DService.MseGetAllAsync(); + if (mseData.Count > 0) + { + var currRec = mseData.FirstOrDefault(x => x.IdxMacchina == id); + if (currRec != null) + { + // recupero da redis elenco stati + var anagStati = await DService.AnagStatiGetAllAsync(); + var currStato = anagStati.FirstOrDefault(x => x.IdxStato == currRec.IdxStato); + // calcolo SE sia idle... OVVERO SEMAFORO NON VERDE!!! + if (currStato != null && currStato.Semaforo != "sVe") + { + // calcolo durata... + answ = (int)(currRec.Durata ?? 0); + } + } + } + } + catch (Exception exc) + { + Log.Error($"Errore in GetIdlePeriod{Environment.NewLine}{exc}"); + return StatusCode(StatusCodes.Status500InternalServerError, "NO"); + } + return Ok(answ); + } + /// /// Recupera TASK richiesto x macchina: /// GET: IOB/getOptPar/SIMUL_03 @@ -440,7 +579,7 @@ namespace MP.IOC.Controllers id = id.Replace("|", "#"); string answ = ""; // scrivo keep alive!!! (se necessario, altrimenti è in cache...) - DService.ScriviKeepAlive(id, DateTime.Now); + await DService.ScriviKeepAliveAsync(id, DateTime.Now); try { // leggo da REDIS eventuale elenco task x macchina... @@ -468,7 +607,7 @@ namespace MP.IOC.Controllers string answ = ""; try { - DService.ScriviKeepAlive(id, DateTime.Now); + await DService.ScriviKeepAliveAsync(id, DateTime.Now); // leggo da REDIS eventuale elenco task x macchina... Dictionary valori = await DService.GetTask2ExeMacchinaAsync(id); answ = JsonConvert.SerializeObject(valori); @@ -481,6 +620,35 @@ namespace MP.IOC.Controllers return Ok(answ); } + /// + /// Recupera codice numerico ODL/PODL dato CodXdl, in pratica la parte finale SENZA ODL/PODL + /// Funzione per impianti che accettano solo INT in scrittura: + /// GET: IOB/getXdlNum/SIMUL_03?CodXdl=ODL00000123 + /// + /// IdxMacchina (NON considerato) + /// + /// CodXdl richiesto, se vuoto restituisce TUTTI i valori in tabella di decodifica + /// + /// SINGOLO VALORE calcolato on the fly + [HttpGet("getXdlNum/{id}")] + public async Task GetXdlNum(string id, string CodXdl = "") + { + // in realtà ID macchina non conta e lo ignoriamo... + string answ = ""; + await DService.ScriviKeepAliveAsync(id, DateTime.Now); + try + { + // sostituisco PODL/ODL con "" e lascio zero iniziali (conversione INT in IOB) + answ = CodXdl.Replace("PODL", "").Replace("ODL", ""); + } + catch (Exception exc) + { + Log.Error($"Errore in GetXdlNum{Environment.NewLine}{exc}"); + return StatusCode(StatusCodes.Status500InternalServerError, "NO"); + } + return Ok(answ); + } + /// /// Metodo di dichiarazione "improprio" tramite get call totalmetne definita da URL /// GET: IOB/input/SIMUL_03?valore=3&dtEve=20181206180600000&dtCurr=20181206180600000&cnt=999 @@ -505,12 +673,12 @@ namespace MP.IOC.Controllers DateTime dataOraEvento = DateTime.Now; try { - answ = DService.processInput(id, valore, dtEve, dtCurr, cnt); + answ = await DService.ProcessInputAsync(id, valore, dtEve, dtCurr, cnt); return Ok(answ); } catch (Exception exc) { - Log.Error($"Errore in processInput{Environment.NewLine}{exc}"); + Log.Error($"Errore in ProcessInputAsync{Environment.NewLine}{exc}"); return StatusCode(StatusCodes.Status500InternalServerError, "NO"); } } @@ -1017,6 +1185,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 /// diff --git a/MP.IOC/Data/MpDataService.cs b/MP.IOC/Data/MpDataService.cs index 96983526..7ffbd6ab 100644 --- a/MP.IOC/Data/MpDataService.cs +++ b/MP.IOC/Data/MpDataService.cs @@ -1,8 +1,10 @@ -using MP.Core.Conf; +using Microsoft.EntityFrameworkCore; +using MP.Core.Conf; using MP.Core.DTO; using MP.Core.Objects; using MP.Data; using MP.Data.DbModels; +using MP.Data.DbModels.Anag; using MP.Data.MgModels; using Newtonsoft.Json; using NLog; @@ -293,6 +295,30 @@ namespace MP.IOC.Data return result; } + /// + /// Restituisce l'anagrafica STATI per intero + /// + /// + public async Task> AnagStatiGetAllAsync() + { + List dbResult = new List(); + // cerco in redis... + var currKey = Utils.redisAnagStati; + RedisValue rawData = await redisDb.StringGetAsync(currKey); + if (rawData.HasValue) + { + dbResult = JsonConvert.DeserializeObject>($"{rawData}") ?? new(); + } + else + { + dbResult = await IocDbController.AnagStatiGetAllAsync(); + // serializzo e salvo... + rawData = JsonConvert.SerializeObject(dbResult); + await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache)); + } + return dbResult; + } + public async Task> AnagTipoArtLV() { Stopwatch stopWatch = new Stopwatch(); @@ -500,10 +526,10 @@ namespace MP.IOC.Data /// data-ora evento (server) /// sequenza dati inviati /// - public inputComandoMapo checkMicroStato(string idxMacchina, string valore, DateTime dtEve, string contatore) + public async Task CheckMicroStatoAsync(string idxMacchina, string valore, DateTime dtEve, string contatore) { // recupero SE IMPIEGATO REDIS i valori del Dictionary della macchina... - Dictionary datiMacc = mDatiMacchine(idxMacchina); + Dictionary datiMacc = await mDatiMacchineAsync(idxMacchina); // processing inputComandoMapo answ = new inputComandoMapo(); @@ -515,7 +541,7 @@ namespace MP.IOC.Data string CodArticolo = datiMacc["CodArticolo"]; if (string.IsNullOrEmpty(CodArticolo)) { - var allDatiMacch = IocDbController.DatiMacchineGetAll(); + var allDatiMacch = await IocDbController.DatiMacchineGetAllAsync(); var recMacc = allDatiMacch.FirstOrDefault(x => x.IdxMacchina == idxMacchina); if (recMacc != null) { @@ -570,7 +596,7 @@ namespace MP.IOC.Data InizioStato = dtEve, Value = valore }; - IocDbController.MicroStatoMacchinaUpsert(newRec); + await IocDbController.MicroStatoMacchinaUpsertAsync(newRec); if (idxTipoEv > 0) { try @@ -589,7 +615,7 @@ namespace MP.IOC.Data Value = valEsteso }; // salva e processa - answ = scriviRigaEvento(newRecEv); + answ = await scriviRigaEventoAsync(newRecEv); //currTask = scriviRigaEvento(idxMacchina, idxTipoEv, codArticolo, valEsteso, 0, "-", dtEve, DateTime.Now); // forzo RESET dati macchina... ResetDatiMacchina(idxMacchina); @@ -687,6 +713,27 @@ namespace MP.IOC.Data return result; } + public async Task> DecNumArtGetFiltAsync(string codArt = "") + { + List result = new(); + string tag = string.IsNullOrEmpty(codArt) ? "ALL" : codArt; + string currKey = $"{Utils.redisDecNumArtKey}:{tag}"; + // cerco in redis dato valore sel macchina... + RedisValue rawData = await redisDb.StringGetAsync(currKey); + if (rawData.HasValue) + { + result = JsonConvert.DeserializeObject>($"{rawData}") ?? new(); + } + else + { + result = await IocDbController.DecNumArtGetFiltAsync(codArt); + // serializzo e salvo... + rawData = JsonConvert.SerializeObject(result); + redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache)); + } + return result; + } + /// /// Dispose del connettore ai dati /// @@ -899,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); @@ -1161,8 +1282,32 @@ namespace MP.IOC.Data } /// + /// Restituisce il valore booleano se la macchina sia abilitata all'input /// - /// id odl da cercare + /// + /// + public async Task IobInsEnabAsync(string idxMacchina) + { + var key = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS); + + // 1. Tentativo ottimizzato: leggiamo solo il campo che ci serve + // Supponendo che tu usi StackExchange.Redis direttamente o un wrapper + string? val = await redisDb.HashGetAsync(key, "insEnabled"); + + // 2. Se non c'è in cache, carichiamo/resettiamo tutto + if (val == null) + { + var data = await ResetDatiMacchinaAsync(idxMacchina); + data.TryGetValue("insEnabled", out val); + } + + // 3. Parsing sicuro + return val != null && (val == "1" || val.ToLower() == "true"); + } + + /// + /// + /// idxMacc odl da cercare /// public async Task> ListGiacenze(int IdxOdl) { @@ -1229,6 +1374,40 @@ namespace MP.IOC.Data Log.Debug($"Macchine2SlaveGetAll | Read from {readType}: {ts.TotalMilliseconds}ms"); return result; } + /// + /// Elenco completo valori Macchine 2 Slave + /// + /// + public async Task> Macchine2SlaveGetAllAsync() + { + List? result = new List(); + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + string readType = "DB"; + string currKey = $"{Utils.redisBaseAddr}:M2STab"; + // cerco in redis dato valore sel macchina... + RedisValue rawData = await redisDb.StringGetAsync(currKey); + if (rawData.HasValue) + { + result = JsonConvert.DeserializeObject>($"{rawData}"); + readType = "REDIS"; + } + else + { + result = await IocDbController.Macchine2SlaveAsync(); + // serializzo e salvo... + rawData = JsonConvert.SerializeObject(result); + await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache)); + } + if (result == null) + { + result = new List(); + } + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + Log.Debug($"Macchine2SlaveGetAllAsync | Read from {readType}: {ts.TotalMilliseconds}ms"); + return result; + } /// /// Elenco di tutte le macchine gestite @@ -1338,7 +1517,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 /// /// /// @@ -1596,6 +1775,33 @@ namespace MP.IOC.Data return answ; } + /// + /// Restitusice elenco KVP dei campi DatiMacchine + StatoMacchine per l'impianto indicato + /// + /// + /// + public async Task> mDatiMacchineAsync(string idxMacchina) + { + // hard coded dimensione vettore DatiMacchine + Dictionary answ = new Dictionary(); + // ORA recupero da memoria redis... + try + { + var currHash = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS); + answ = await RedisGetHashDictAsync(currHash); + // se è vuoto... leggo da DB e popolo! + if (answ.Count == 0) + { + answ = ResetDatiMacchina(idxMacchina); + } + } + catch (Exception exc) + { + Log.Error($"Errore in compilazione dati Macchine x Redis - idxMacchina {idxMacchina}:{Environment.NewLine}{exc}"); + } + return answ; + } + /// /// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato /// @@ -1640,6 +1846,39 @@ namespace MP.IOC.Data return answ; } + /// + /// Elenco da tabella MappaStatoExplModel + /// + /// + public async Task> MseGetAllAsync(bool forceDb = false) + { + Stopwatch sw = new Stopwatch(); + string source = "DB"; + sw.Start(); + List? result = new List(); + // cerco in _redisConn... + RedisValue rawData = await redisDb.StringGetAsync(Constants.redisMseKey); + if (rawData.HasValue && !forceDb) + { + result = JsonConvert.DeserializeObject>($"{rawData}") ?? new(); + source = "REDIS"; + } + else + { + result = await IocDbController.MseGetAllAsync(maxAge); + // serializzp e salvo... + rawData = JsonConvert.SerializeObject(result); + await redisDb.StringSetAsync(Constants.redisMseKey, rawData, getRandTOut(redisShortTimeCache / 2)); + } + if (result == null) + { + result = new List(); + } + sw.Stop(); + Log.Debug($"MseGetAllAsync | {source} | {sw.Elapsed.TotalMilliseconds}ms"); + return result; + } + /// /// Restitusice elenco KVP /// currKey: IdxMacchina @@ -2232,7 +2471,7 @@ namespace MP.IOC.Data /// /// /// - public string processInput(string idxMacchina, string valore, string dtEve, string dtCurr, string contatore) + public async Task ProcessInputAsync(string idxMacchina, string valore, string dtEve, string dtCurr, string contatore) { string answ = ""; // 2018.10.26 controllo dtEve e dtCurr @@ -2263,7 +2502,7 @@ namespace MP.IOC.Data // se ho meno decimali x evento rispetto dtCorrente... if (dtEve.Length < dtCurr.Length) { - Log.Info($"processInput: fix valore dtEve: {dtEve} | dtCurr: {dtCurr}"); + Log.Info($"ProcessInputAsync: fix valore dtEve: {dtEve} | dtCurr: {dtCurr}"); dtEve = dtEve.PadRight(dtCurr.Length, '0'); } delta = Convert.ToInt64(dtCurr) - Convert.ToInt64(dtEve); @@ -2320,13 +2559,13 @@ namespace MP.IOC.Data { int cntVal = 0; int.TryParse(contatore, out cntVal); - saveSigLog(idxMacchina, valore, dataOraEvento, cntVal); + await saveSigLogAsync(idxMacchina, valore, dataOraEvento, cntVal); } // continuo col resto try { // scrivo keep alive!!! (se necessario, altrimenti è in cache...) - ScriviKeepAlive(idxMacchina, DateTime.Now); + await ScriviKeepAliveAsync(idxMacchina, DateTime.Now); // verifico se sia una macchina MULTI ed in tal caso calcolo i // SUB-systems e CHIAMERO' alla fine pure loro.... if (isMulti(idxMacchina)) @@ -2339,14 +2578,14 @@ namespace MP.IOC.Data newVal = preProcInput(item.Key, valore); // ora processo e salvo il valore del microstato... // INTERNAMENTE gestisce i casi DB/REDIS secondo necessità - checkMicroStato(item.Key, newVal, dataOraEvento, contatore); + await CheckMicroStatoAsync(item.Key, newVal, dataOraEvento, contatore); } } else { // ora processo e salvo il valore del microstato... INTERNAMENTE // gestisce i casi DB/REDIS secondo necessità - checkMicroStato(idxMacchina, valore, dataOraEvento, contatore); + await CheckMicroStatoAsync(idxMacchina, valore, dataOraEvento, contatore); } // registro in risposta che è andato tutto bene... answ = "OK"; @@ -2836,11 +3075,15 @@ namespace MP.IOC.Data return answ; } - public async Task RedisSetHashDictAsync(RedisKey redKey, Dictionary valori) + public async Task RedisSetHashDictAsync(RedisKey redKey, Dictionary valori, double expireSeconds = -1.0) { bool answ = false; HashEntry[] redHash = valori.Select(x => new HashEntry(x.Key, x.Value)).ToArray(); await redisDb.HashSetAsync(redKey, redHash); + if (expireSeconds > 0.0) + { + redisDb.KeyExpire(redKey, DateTime.Now.AddSeconds(expireSeconds)); + } answ = true; return answ; } @@ -3266,6 +3509,27 @@ namespace MP.IOC.Data return IocDbController.SignalLogInsert(newRec); } + /// + /// salva il segnale di "microstato" (segnale) ASYNC + /// + /// idx macchina + /// valore ingresso + /// data-ora evento (server) + /// contatore sequenza dati inviati + /// + public async Task saveSigLogAsync(string idxMacchina, string valore, DateTime dtEve, int contatore) + { + SignalLogModel newRec = new SignalLogModel() + { + IdxMacchina = idxMacchina, + DtCurr = DateTime.Now, + DtEve = dtEve, + Contatore = contatore, + Valore = valore + }; + return await IocDbController.SignalLogInsertAsync(newRec); + } + /// /// scrive un evento di keepalive sulla tabella /// @@ -3593,6 +3857,28 @@ namespace MP.IOC.Data #endregion Public Methods + #region Internal Methods + + /// + /// Recupera ArtNum dato CodArt (per impianti che accettano solo INT in scrittura) + /// + /// + /// CodArt richiesto, se vuoto restituisce TUTTI i valori in tabella di decodifica + /// + /// Dizionario contenente le righe delle codifiche attive Articolo/Numero + internal async Task> GetArtNumAsync(string codArt) + { + Dictionary answ = new Dictionary(); + var currData = await DecNumArtGetFiltAsync(codArt); + foreach (var item in currData) + { + answ.Add(item.CodArticolo, item.NumART); + } + return answ; + } + + #endregion Internal Methods + #region Protected Fields protected Random rand = new Random(); @@ -3628,6 +3914,11 @@ namespace MP.IOC.Data private static Logger Log = LogManager.GetCurrentClassLogger(); + /// + /// MS max age x dato MSE + /// + private int maxAge = 2000; + private string MpIoNS = ""; /// @@ -3725,6 +4016,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 /// @@ -3904,6 +4333,77 @@ namespace MP.IOC.Data return result; } + /// + /// Restitusice elenco KVP dei campi DatiMacchine + StatoMacchine per l'impianto indicato + /// + /// + /// + private async Task> ResetDatiMacchinaAsync(string idxMacc) + { + var currHash = Utils.RedKeyDatiMacc(idxMacc, MpIoNS); + // inizio con un bel reset... + RedisFlushPattern($"{currHash}"); + Dictionary? result = new Dictionary(); + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + string readType = "DB"; + var dbResults = await IocDbController.VMSFDGetByMaccAsync(idxMacc); + // converto in formato dizionario... + if (dbResults != null && dbResults.Count > 0) + { + var rowResult = dbResults[0]; + // salvo 1:1 i valori... STATO + result.Add("IdxMicroStato", $"{rowResult.IdxMicroStato}"); + result.Add("IdxStato", $"{rowResult.IdxStato}"); + result.Add("CodArticolo", $"{rowResult.CodArticolo}"); + result.Add("insEnabled", $"{rowResult.InsEnabled}"); + result.Add("sLogEnabled", $"{rowResult.SLogEnabled}"); + result.Add("pallet", $"{rowResult.Pallet}"); + result.Add("CodArticolo_A", $"{rowResult.CodArticoloA}"); + result.Add("CodArticolo_B", $"{rowResult.CodArticoloB}"); + result.Add("TempoCicloBase", $"{rowResult.TempoCicloBase}"); + result.Add("PzPalletProd", $"{rowResult.PzPalletProd}"); + result.Add("MatrOpr", $"{rowResult.MatrOpr}"); + result.Add("lastVal", $"{rowResult.LastVal}"); + result.Add("TCBase", $"{rowResult.TempoCicloBase}"); + + //...e SETUP + result.Add("CodMacc", $"{rowResult.Codmacchina}"); + result.Add("IdxFamIn", $"{rowResult.IdxFamigliaIngresso}"); + result.Add("Multi", $"{rowResult.Multi}"); + result.Add("BitFilt", $"{rowResult.BitFilt}"); + result.Add("MaxVal", $"{rowResult.MaxVal}"); + result.Add("BSR", $"{rowResult.Bsr}"); + result.Add("ExplodeBit", $"{rowResult.ExplodeBit}"); + result.Add("NumBit", $"{rowResult.NumBit}"); + result.Add("IdxFamMacc", $"{rowResult.IdxFamiglia}"); + result.Add("simplePallet", $"{rowResult.SimplePallet}"); + result.Add("palletChange", $"{rowResult.PalletChange}"); + } + // cerco info Master/slave... + var m2sTab = await Macchine2SlaveGetAllAsync(); + string isMaster = m2sTab.Where(x => x.IdxMacchina == idxMacc).Count() > 0 ? "1" : "0"; + string isSlave = m2sTab.Where(x => x.IdxMacchinaSlave == idxMacc).Count() > 0 ? "1" : "0"; + result.Add("Master", isMaster); + result.Add("Slave", isSlave); + + // durata cache in secondi dal valore insEnabled... + double numSecCache = 60 * ((result["insEnabled"].ToLower() == "true") ? redisShortTimeCache / 4 : redisShortTimeCache); + // ...e salvo... + await RedisSetHashDictAsync(currHash, result, numSecCache); + + if (result == null) + { + result = new Dictionary(); + } + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + Log.Debug($"GetCurrMSFDMacc | Read from {readType}: {ts.TotalMilliseconds}ms"); + return result; + } + + + /// /// Resetta (rileggendo) i dati della State Machine ingressi nel formato /// currKey: cState_nVal (current MICRO-STATE + "_" + new Value) @@ -3967,6 +4467,32 @@ namespace MP.IOC.Data return answ; } + /// + /// Scrive una riga di evento nel db + check cambio stato DiarioDiBordo + /// + /// codice macchina + /// + private async Task scriviRigaEventoAsync(EventListModel newRec) + { + bool inserito = false; + try + { + // inserisco evento + inserito = await IocDbController.EvListInsertAsync(newRec); + // faccio controllo per eventuale cambio stato da tab transizioni... + checkCambiaStatoBatch(tipoInputEvento.hw, newRec.IdxMacchina, newRec.InizioStato ?? DateTime.Now, newRec.IdxTipo, newRec.CodArticolo, newRec.Value, newRec.MatrOpr, newRec.pallet); + } + catch (Exception exc) + { + Log.Error($"Errore in scriviRigaEvento | IdxMacchina {newRec.IdxMacchina} | IdxTipo {newRec.IdxTipo} | codArticolo {newRec.CodArticolo} | Value {newRec.Value} | MatrOpr {newRec.MatrOpr} | Pallet {newRec.pallet} | dTime {newRec.InizioStato}{Environment.NewLine}{exc}"); + } + // formatto output + inputComandoMapo answ = new inputComandoMapo(); + answ.outValue = inserito.ToString(); + answ.needStatusRefresh = true; + return answ; + } + /// /// Restituisce il valore booleano se la macchina sia abilitata all'inserimento COMPLETO nel /// Signal Log diff --git a/MP.IOC/MP.IOC.csproj b/MP.IOC/MP.IOC.csproj index f6a5e0de..b97afade 100644 --- a/MP.IOC/MP.IOC.csproj +++ b/MP.IOC/MP.IOC.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - 6.16.2604.1517 + 6.16.2604.1608 diff --git a/MP.IOC/Resources/ChangeLog.html b/MP.IOC/Resources/ChangeLog.html index 5b1014d6..61354818 100644 --- a/MP.IOC/Resources/ChangeLog.html +++ b/MP.IOC/Resources/ChangeLog.html @@ -1,6 +1,6 @@ Modulo MP-IOC -

Versione: 6.16.2604.1517

+

Versione: 6.16.2604.1608


Note di rilascio:
  • diff --git a/MP.IOC/Resources/VersNum.txt b/MP.IOC/Resources/VersNum.txt index 9cef419a..df2a6ad6 100644 --- a/MP.IOC/Resources/VersNum.txt +++ b/MP.IOC/Resources/VersNum.txt @@ -1 +1 @@ -6.16.2604.1517 +6.16.2604.1608 diff --git a/MP.IOC/Resources/manifest.xml b/MP.IOC/Resources/manifest.xml index 71938dea..9dae35f9 100644 --- a/MP.IOC/Resources/manifest.xml +++ b/MP.IOC/Resources/manifest.xml @@ -1,6 +1,6 @@ - 6.16.2604.1517 + 6.16.2604.1608 https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/MP.IOC.zip https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/ChangeLog.html false