diff --git a/Directory.Packages.props b/Directory.Packages.props
index de7d50f2..00d6ceed 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -28,9 +28,9 @@
-
+
-
+
diff --git a/MP-RIOC/Data/MpDataService.cs b/MP-RIOC/Data/MpDataService.cs
new file mode 100644
index 00000000..12eecbd8
--- /dev/null
+++ b/MP-RIOC/Data/MpDataService.cs
@@ -0,0 +1,5006 @@
+using Microsoft.EntityFrameworkCore;
+using MP.Core.Conf;
+using MP.Core.DTO;
+using MP.Core.Objects;
+using MP.Data;
+using MP.Data.Controllers;
+using MP.Data.DbModels;
+using MP.Data.DbModels.Anag;
+using MP.Data.MgModels;
+using MP.Data.Services.IOC;
+using MP.Data.Services.Mtc;
+using Newtonsoft.Json;
+using NLog;
+using StackExchange.Redis;
+using System.Data;
+using System.Diagnostics;
+using System.Globalization;
+using static MP.Core.Objects.Enums;
+
+namespace MP.RIOC.Data
+{
+ public class MpDataService : IDisposable
+ {
+ #region Public Constructors
+
+ public MpDataService(
+ IConfiguration configuration,
+ ILogger logger,
+ IServiceScopeFactory scopeFactory,
+ IMtcSetupService mtcServ)
+ {
+ _logger = logger;
+ _logger.LogInformation("Starting MpDataService INIT");
+ _configuration = configuration;
+ _scopeFactory = scopeFactory;
+
+ // setup compoenti REDIS
+ redisConn = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("Redis"));
+ redisConnAdmin = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("RedisAdmin"));
+ redisDb = redisConn.GetDatabase();
+ BroadastMsgPipe = new MessagePipe(redisConn, Constants.BROADCAST_M_PIPE);
+ // leggo cache (lungo periodo e corto periodo)
+ int.TryParse(_configuration.GetValue("ServerConf:redisLongTimeCache"), out redisLongTimeCache);
+ int.TryParse(_configuration.GetValue("ServerConf:redisShortTimeCache"), out redisShortTimeCache);
+ Log.Info($"Redis INIT | redisLongTimeCache: {redisLongTimeCache} min | redisShortTimeCache {redisShortTimeCache} min");
+
+ // gestione scope factory
+ useFactory = _configuration.GetValue("ServerConf:useFactory");
+ // conf base x servizi condivisi IO/IOC
+ MpIoNS = _configuration.GetValue("ServerConf:MpIoNS") ?? "MP";
+ Log.Info($"MpDataService | useFactory {useFactory} | MpIoNS {MpIoNS}");
+
+ // conf DB
+ string connStr = _configuration.GetConnectionString("MP.Data") ?? "";
+ if (string.IsNullOrEmpty(connStr))
+ {
+ Log.Error("DbController: ConnString empty!");
+ }
+ else
+ {
+ SpecDbController = new MpSpecController(configuration);
+ IocDbController = new MpIocController(configuration);
+ Log.Info("DbControllers INIT OK");
+ }
+
+ MtcService = mtcServ;
+
+ // conf mongo...
+ connStr = _configuration.GetConnectionString("mdbConnString") ?? "";
+ if (string.IsNullOrEmpty(connStr))
+ {
+ Log.Error("MongoController: ConnString empty!");
+ }
+ else
+ {
+ mongoController = new MpMongoController(configuration);
+ Log.Info("MongoController INIT OK");
+ }
+
+ }
+
+ #endregion Public Constructors
+
+ #region Public Properties
+
+ public static MpIocController IocDbController { get; set; } = null!;
+ public static MpMongoController mongoController { get; set; } = null!;
+ public static MpSpecController SpecDbController { get; set; } = null!;
+ public MessagePipe BroadastMsgPipe { get; set; } = null!;
+
+ ///
+ /// Dizionario dei tag configurati per IOB
+ ///
+ public Dictionary> currTagConf { get; set; } = new Dictionary>();
+
+ #endregion Public Properties
+
+ #region Public Methods
+
+ ///
+ /// Recupera eventuali azioni richieste
+ ///
+ ///
+ public async Task ActionGetReq()
+ {
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ DisplayAction? result = null;
+ // cerco in redis...
+ RedisValue rawData = await redisDb.StringGetAsync(Utils.redisActionReq);
+ if (!string.IsNullOrEmpty($"{rawData}"))
+ {
+ result = JsonConvert.DeserializeObject($"{rawData}");
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"ActionGetReq Read from REDIS: {ts.TotalMilliseconds}ms");
+ }
+ if (result == null)
+ {
+ result = new DisplayAction();
+ }
+ return result;
+ }
+
+ ///
+ /// Salva richiesta azione
+ ///
+ ///
+ ///
+ public bool ActionSetReq(DisplayAction? act2save)
+ {
+ bool fatto = false;
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ // cerco in redis...
+ string rawData = JsonConvert.SerializeObject(act2save);
+ // invio broadcast + salvo in redis
+ BroadastMsgPipe.saveAndSendMessage(Utils.redisActionReq, rawData);
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"ActionSetReq REDIS send to broadcast + Write cache: {ts.TotalMilliseconds}ms");
+ return fatto;
+ }
+
+ ///
+ /// Verifica se sia da reinviare un tName alla macchina dall'elenco di quelli salvati (in
+ /// modalità upsert) se non scaduti
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool AddCheckTask4Machine(string idxMacchina, taskType taskKey, string taskVal)
+ {
+ bool answ = false;
+ var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
+ Log.Info($"addCheckTask4Machine idxMacchina: {idxMacchina} | taskKey: {taskKey} | taskVal: {taskVal}");
+ try
+ {
+ Dictionary savedTask = mSavedTaskMacchina(idxMacchina);
+ // cerco valOut saved
+ string savedVal = savedTask[taskKey.ToString()];
+ // se ho un valOut != "" --> rimetto in coda di invio...
+ if (!string.IsNullOrEmpty(savedVal) && (savedVal != taskVal))
+ {
+ // leggo tName attuali...
+ Dictionary currTask = mTaskMacchina(idxMacchina);
+ // rimetto in tName da eseguire...
+ currTask[taskKey.ToString()] = savedVal;
+ RedisSetHashDict(currHash, currTask);
+ answ = true;
+ Log.Info($"re-issued task4machine: idxMacchina: {idxMacchina} | taskKey: {taskKey} | savedVal: {savedVal}");
+ }
+ }
+ catch (Exception exc)
+ {
+ Log.Error($"Eccezione in AddCheckTask4Machine{Environment.NewLine}{exc}");
+ }
+
+ return answ;
+ }
+
+ ///
+ /// Aggiunge un PARAMETRO OPZIONALE all'elenco di quelli salvati (in modalità upsert)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool AddOptPar4Machine(string idxMacchina, string taskKey, string taskVal)
+ {
+ bool answ = false;
+ RedisKey currHash = Utils.RedKeyOptPar(idxMacchina, MpIoNS);
+ try
+ {
+ // leggo tName attuali...
+ var currVal = mOptParMacchina(idxMacchina);
+ // verifico se esista o se vada aggiunto...
+ if (currVal.ContainsKey(taskKey))
+ {
+ currVal[taskKey] = taskVal;
+ }
+ else
+ {
+ currVal.Add(taskKey, taskVal);
+ }
+ RedisSetHashDict(currHash, currVal);
+ answ = true;
+ }
+ catch (Exception exc)
+ {
+ Log.Error($"Eccezione in addOptPar4Machine{Environment.NewLine}{exc}");
+ }
+ return answ;
+ }
+
+ ///
+ /// Aggiunge un tName all'elenco di quelli salvati (in modalità upsert)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool AddTask4Machine(string idxMacchina, Enums.taskType taskKey, string taskVal)
+ {
+ bool answ = false;
+ var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
+ var currSavedParHash = Utils.RedKeySavedTask2ExeMacc(idxMacchina, MpIoNS);
+ Dictionary currTask = new Dictionary();
+ Dictionary savedTask = new Dictionary();
+ try
+ {
+ // leggo tName attuali...
+ currTask = mTaskMacchina(idxMacchina);
+ if (currTask.ContainsKey($"{taskKey}"))
+ {
+ currTask[$"{taskKey}"] = taskVal;
+ }
+ else
+ {
+ currTask.Add($"{taskKey}", taskVal);
+ }
+ RedisSetHashDict(currHash, currTask);
+ answ = true;
+ Log.Info($"Task ADD | hash: {currHash} | idxMacchina: {idxMacchina} | taskKey: {taskKey} | taskVal: {taskVal}");
+ }
+ catch { }
+ // verifico in base al tipo di tName se fare backup...
+ switch (taskKey)
+ {
+ case Enums.taskType.setArt:
+ case Enums.taskType.setComm:
+ case Enums.taskType.setPzComm:
+ case Enums.taskType.setProg:
+ // leggo tName SALVATI attuali...
+ savedTask = mSavedTaskMacchina(idxMacchina);
+ savedTask[taskKey.ToString()] = taskVal;
+ RedisSetHashDict(currSavedParHash, savedTask);
+ answ = true;
+ break;
+
+ case Enums.taskType.endProd:
+ // salvo un DICT vuoto x resettare
+ savedTask = new Dictionary();
+ RedisSetHashDict(currSavedParHash, savedTask);
+ answ = true;
+ break;
+
+ default:
+ break;
+ }
+ return answ;
+ }
+
+ ///
+ /// Aggiunge un set di task x macchina all'elenco di quelli salvati (in modalità upsert)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task AddTask4MacListAsync(string idxMacchina, Dictionary taskDict)
+ {
+ bool answ = false;
+ bool needSaveParams = false;
+ var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
+ var currSavedParHash = Utils.RedKeySavedTask2ExeMacc(idxMacchina, MpIoNS);
+ Dictionary currTask = new Dictionary();
+ Dictionary savedTask = new Dictionary();
+
+ // leggo valori attuali...
+ currTask = await mTaskMacchinaAsync(idxMacchina);
+ // verifico processing dei ricevuti
+ foreach (var item in taskDict)
+ {
+ if (currTask.ContainsKey($"{item.Key}"))
+ {
+ currTask[$"{item.Key}"] = item.Value;
+ }
+ else
+ {
+ currTask.Add($"{item.Key}", item.Value);
+ }
+ Log.Trace($"Task ADD | hash: {currHash} | idxMacchina: {idxMacchina} | taskKey: {item.Key} | taskVal: {item.Value}");
+
+ // verifico in base al tipo di tName se fare backup...
+ switch (item.Key)
+ {
+ case Enums.taskType.setArt:
+ case Enums.taskType.setComm:
+ case Enums.taskType.setPzComm:
+ case Enums.taskType.setProg:
+ // leggo tName SALVATI attuali...
+ savedTask = mSavedTaskMacchina(idxMacchina);
+ savedTask[item.Key.ToString()] = item.Value;
+ needSaveParams = true;
+ break;
+
+ case Enums.taskType.endProd:
+ // salvo un DICT vuoto x resettare
+ savedTask = new Dictionary();
+ needSaveParams = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ // salvo!
+ await RedisSetHashDictAsync(currHash, currTask);
+ answ = true;
+
+ if (needSaveParams)
+ {
+ await RedisSetHashDictAsync(currSavedParHash, savedTask);
+ }
+ return answ;
+ }
+
+ ///
+ /// Insert record allarme
+ ///
+ /// Data evento
+ /// Idx macchina
+ /// area memoria
+ /// indice memoria
+ /// valOut status
+ /// valOut decodificato
+ ///
+ public async Task AlarmInsertAsync(DateTime dtRif, string idxMacchina, string memAddress, int memIndex, int statusVal, string valDecoded)
+ {
+ // aggiorno record sul DB
+ bool answ = await IocDbController.AlarmLogInsertAsync(dtRif, idxMacchina, memAddress, memIndex, statusVal, valDecoded);
+
+ return answ;
+ }
+
+ public async Task> AnagStatiComm()
+ {
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ List? result = new List();
+ // cerco in redis...
+ RedisValue rawData = await redisDb.StringGetAsync(Utils.redisStatoCom);
+ if (!string.IsNullOrEmpty($"{rawData}"))
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"AnagStatiComm Read from REDIS: {ts.TotalMilliseconds}ms");
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.AnagStatiComm());
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ await redisDb.StringSetAsync(Utils.redisStatoCom, rawData, getRandTOut(redisLongTimeCache));
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"AnagStatiComm Read from DB: {ts.TotalMilliseconds}ms");
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ 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();
+ stopWatch.Start();
+ string source = "DB";
+ List? result = new List();
+ // cerco in redis...
+ RedisValue rawData = await redisDb.StringGetAsync(Utils.redisTipoArt);
+ if (!string.IsNullOrEmpty($"{rawData}"))
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ source = "REDIS";
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.AnagTipoArtLV());
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ await redisDb.StringSetAsync(Utils.redisTipoArt, rawData, getRandTOut(redisLongTimeCache));
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"AnagTipoArtLV Read from {source}: {ts.TotalMilliseconds}ms");
+ if (result == null)
+ {
+ result = new List();
+ }
+ return result;
+ }
+
+ ///
+ /// Elenco Codice articolo con dati dossier gestiti
+ ///
+ ///
+ public async Task> ArticleWithDossier()
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = Utils.redisArtByDossier;
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.ArticleWithDossier());
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"ArticleWithDossier | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Eliminazione record selezionato
+ ///
+ ///
+ ///
+ public async Task ArticoliDeleteRecord(AnagArticoliModel currRec)
+ {
+ bool fatto = await SpecDbController.ArticoliDeleteRecord(currRec);
+ await resetCacheArticoli();
+ return fatto;
+ }
+
+ ///
+ /// Elenco ultimi articoli data amcchina
+ ///
+ ///
+ ///
+ public async Task> ArticoliGetLastByMaccAsync(string idxMacc)
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisArtList}:Last:{idxMacc}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await IocDbController.ArticoliGetLastByMaccAsync(idxMacc);
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"ArticoliGetLastByMaccAsync | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Restitusice elenco articoli cercati
+ ///
+ ///
+ ///
+ ///
+ public async Task> ArticoliGetSearch(int numRecord, string azienda, string searchVal)
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string sKey = string.IsNullOrEmpty(searchVal) ? "***" : searchVal;
+ string currKey = $"{Utils.redisArtList}:{azienda}:{sKey}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.ArticoliGetSearch(numRecord, azienda, searchVal));
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache / 5));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"ArticoliGetSearch | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Aggiornamento record selezionato
+ ///
+ ///
+ ///
+ public async Task ArticoliUpdateRecord(AnagArticoliModel currRec)
+ {
+ bool fatto = await SpecDbController.ArticoliUpdateRecord(currRec);
+ await resetCacheArticoli();
+ return fatto;
+ }
+
+ ///
+ /// Verifica se sia possiubile cancellare articolo dato suo CodArt cercando su redis o su
+ /// tab veto da DB
+ ///
+ ///
+ ///
+ public bool ArticoloDelEnabled(object CodArt)
+ {
+ bool answ = false;
+ string codArticolo = $"{CodArt}";
+ int cacheCheckArtUsato = 1;
+ int.TryParse(_configuration.GetValue("ServerConf:cacheCheckArtUsato"), out cacheCheckArtUsato);
+ TimeSpan TTLCache = getRandTOut(cacheCheckArtUsato);
+ // cerco in cache redis...
+ string redKeyArtUsed = $"{Utils.redKeyArtUsed}:{codArticolo}";
+ string redKeyTabCheckArt = Utils.redKeyTabCheckArt;
+ var rawData = redisDb.StringGet(redKeyArtUsed);
+ if (!string.IsNullOrEmpty(rawData))
+ {
+ bool.TryParse(rawData, out answ);
+ }
+ else
+ {
+ // controllo non sia stato mai prodotto sennò non posso cancellare...
+ try
+ {
+ // cerco in cache se ci sia la tabella con gli articoli impiegati...
+ var rawTable = redisDb.StringGet(redKeyTabCheckArt);
+ List? artList = new List();
+ if (!string.IsNullOrEmpty(rawTable))
+ {
+ artList = JsonConvert.DeserializeObject>($"{rawTable}");
+ }
+ // rileggo...
+ if (artList == null || artList.Count == 0)
+ {
+ artList = new List();
+ var tabArticoli = SpecDbController.ArticoliGetUsed();
+ var codList = tabArticoli.Select(x => x.CodArticolo);
+ foreach (string cod in codList)
+ {
+ artList.Add(cod);
+ }
+ // SE fosse vuoto aggiungo comunque il cado "ND"...
+ if (artList.Count == 0)
+ {
+ artList.Add("ND");
+ }
+ // salvo
+ rawTable = JsonConvert.SerializeObject(artList);
+ redisDb.StringSet(redKeyTabCheckArt, rawTable, TTLCache);
+ }
+ // cerco nella tabella: se ci fosse --> disabilitato delete
+ bool usato = false;
+ if (artList != null && artList.Count > 0)
+ {
+ usato = artList.Contains(codArticolo);
+ }
+ answ = !usato;
+ redisDb.StringSet(redKeyArtUsed, $"{answ}", TTLCache);
+ }
+ catch
+ { }
+ }
+ return answ;
+ }
+
+ ///
+ /// Effettua split ODL
+ ///
+ /// macchina
+ /// effettuare conferma qty
+ /// imposta la qty prox ODL da ODL che si chiude
+ /// matricola operatore
+ /// Round Step quantità prox ODL (corrente come riferimento)
+ /// Cod ext da associare all'ODL
+ ///
+ public async Task AutoStartOdlAsync(string idxMacchina, bool doConfirm, bool qtyFromLast, int matrOpr, int roundStep = 100, string keyRichiesta = "")
+ {
+ string answ = "KO";
+ DateTime adesso = DateTime.Now;
+
+ // verifico NON CI SIA un veto a NUOVI split...
+ string redKey = $"{Utils.redisVetoSplitOdl}:{idxMacchina}";
+ var rawData = await redisDb.StringGetAsync(redKey);
+ if (rawData.HasValue)
+ {
+ Log.Info($"VETO ATTIVO | Richiesto forceSplitOdl per impianto {idxMacchina} | impossibile procedere");
+ }
+ else
+ {
+ // registro VETO x altri split... 5 minuti
+ await redisDb.StringSetAsync(redKey, $"Inizio SPLIT-ODL {adesso}", TimeSpan.FromMinutes(5));
+ // setup dati da config
+ bool confRett = false;
+ int modoConfProd = -1;
+ bool slaveConfirmPzProd = false;
+ var configData = await ConfigGetAllAsync();
+ if (configData != null)
+ {
+ var currRec = configData.FirstOrDefault(x => x.Chiave == "confRett");
+ if (currRec != null)
+ {
+ bool.TryParse(currRec.Valore, out confRett);
+ }
+ currRec = configData.FirstOrDefault(x => x.Chiave == "modoConfProd");
+ if (currRec != null)
+ {
+ int.TryParse(currRec.Valore, out modoConfProd);
+ }
+ currRec = configData.FirstOrDefault(x => x.Chiave == "SlaveConfirmPzProd");
+ if (currRec != null)
+ {
+ bool.TryParse(currRec.Valore, out slaveConfirmPzProd);
+ }
+ }
+ // calcolo la qta da gestire
+ int qtyConf = 0;
+ int qtyNew = 0;
+ int qtyScarto = 0;
+ if (doConfirm)
+ {
+ try
+ {
+ var rigaProd = await IocDbController.PezziProdMacchinaAsync(idxMacchina);
+ var statoProd = await IocDbController.StatoProdMacchinaAsync(idxMacchina, adesso);
+ qtyConf = rigaProd.pezziNonConfermati;
+ qtyScarto = statoProd.Pz2RecScarto;
+ // calcolo nuovi pezzi da confermare
+ if (qtyFromLast)
+ {
+ roundStep = roundStep == 0 ? 1 : roundStep;
+ double ratio = (double)qtyConf / roundStep;
+ qtyNew = (int)Math.Round(Math.Ceiling(ratio) * roundStep, 0);
+ }
+ }
+ catch (Exception exc)
+ {
+ Log.Error($"AutoStartOdlAsync | Errore recupero pezzi da confermare | idxMacchina {idxMacchina}{Environment.NewLine}{exc}");
+ }
+ }
+
+ // chiamo metodo redis/db...
+ try
+ {
+ // recupero ODL corrente
+ var currData = await IocDbController.OdlCurrByMaccAsync(idxMacchina);
+ if (currData != null && currData.IdxOdl > 0)
+ {
+ // preparo var x master/slave
+ bool isMachMaster = await IobIsMasterAsync(idxMacchina);
+ List slaveList = new();
+ if (isMachMaster)
+ {
+ List allSlaveList = await IocDbController.Macchine2SlaveAsync();
+ slaveList = allSlaveList.Where(x => x.IdxMacchina == idxMacchina).ToList();
+ }
+
+ // registro un evento di inizio attrezzaggio (idxTipoEv = 2)
+ int idxEvento = 2;
+ Log.Info($"Invio evento ODL-SPLIT per macchina {idxMacchina} | ev: {idxEvento} | art: {currData.CodArticolo} | qty conf: {qtyConf} | sty sca: {qtyScarto} | new qty: {qtyNew}");
+
+ // creo evento
+ EventListModel newRecEv = new EventListModel()
+ {
+ CodArticolo = currData.CodArticolo,
+ IdxMacchina = idxMacchina,
+ IdxTipo = idxEvento,
+ InizioStato = adesso,
+ MatrOpr = matrOpr,
+ pallet = "",
+ Value = "ODL-SPLIT"
+ };
+ inputComandoMapo resCmd = await scriviRigaEventoBarcodeAsync(newRecEv);
+
+ // era 100, messo 50...
+ int wTime = 50;
+
+ // eventuale conferma produzione
+ if (doConfirm)
+ {
+ await Task.Delay(wTime);
+ adesso = DateTime.Now;
+ // chiamo conferma produzione...
+ try
+ {
+ string chiamata = confRett ? "confermaProdMacchinaFull" : "confermaProdMacchina";
+ Log.Info($"Chiamata a {chiamata} con parametri {currData.IdxMacchina} |{matrOpr} | {DateTime.Now.AddDays(-10)} | {DateTime.Now} | {qtyConf} | 0 | {qtyScarto} | {DateTime.Now} | false");
+ string idxMacchinaSel = currData.IdxMacchina;
+ bool fatto = false;
+ if (confRett)
+ {
+ // confermo al netto dei pezzi lasciati...
+ fatto = await IocDbController.ConfermaProdMacchinaFullAsync(idxMacchinaSel, modoConfProd, qtyConf, 0, qtyScarto, adesso, matrOpr);
+ if (slaveConfirmPzProd)
+ {
+ foreach (var machine in slaveList)
+ {
+ await IocDbController.ConfermaProdMacchinaFullAsync(machine.IdxMacchinaSlave, modoConfProd, qtyConf, 0, qtyScarto, adesso, matrOpr);
+ }
+ }
+ }
+ else
+ {
+ fatto = await IocDbController.ConfermaProdMacchinaAsync(idxMacchinaSel, modoConfProd, qtyConf, qtyScarto, adesso, matrOpr);
+ if (slaveConfirmPzProd)
+ {
+ foreach (var machine in slaveList)
+ {
+ await IocDbController.ConfermaProdMacchinaAsync(idxMacchinaSel, modoConfProd, qtyConf, qtyScarto, adesso, matrOpr);
+ }
+ }
+ }
+ if (!fatto)
+ {
+ Log.Error($"ERRORE in chiamata {chiamata}");
+ }
+ }
+ catch (Exception exc)
+ {
+ Log.Error($"Eccezione in ConfermaProduzione{Environment.NewLine}{exc}");
+ }
+ }
+ // 2025.02.19 portato da 100 a 1000 ms attesa x evitare che ODL sia avviato PRIMA della conferma
+ // attendo 1000 msec x chiudere ODL
+ await Task.Delay(1000);
+ // chiamo splitOdl
+ await IocDbController.AutoStartOdlAsync(currData.IdxOdl, 0, idxMacchina, currData.TCRichAttr, currData.PzPallet, $"Nuovo ODL da forceSplitOdl.autoStart", true, qtyNew, keyRichiesta);
+
+ // elimino eventuale ODL precedente...
+ string currKey = $"{Utils.redisOdlCurrByMac}:{idxMacchina}";
+ await redisDb.KeyDeleteAsync(currKey);
+
+ // ricalcola ODL macchina
+ var newOdl = await GetCurrOdlAsync(idxMacchina);
+ // attendo 1000 msec
+ await Task.Delay(1000);
+
+ adesso = DateTime.Now;
+ // registro fine ODL (idxTipoEv = 1)
+ idxEvento = 1;
+ Log.Info($"Invio evento FINE ODL-SPLIT | idx: {idxMacchina} | ev: {idxEvento} | art: {currData.CodArticolo}");
+ // costruisco nuovo evento
+ newRecEv = new EventListModel()
+ {
+ CodArticolo = currData.CodArticolo,
+ IdxMacchina = idxMacchina,
+ IdxTipo = idxEvento,
+ InizioStato = adesso,
+ MatrOpr = matrOpr,
+ pallet = "",
+ Value = "ODL-START"
+ };
+ resCmd = await scriviRigaEventoBarcodeAsync(newRecEv);
+ // invio eventi setup a macchina....
+ string setArtVal = $"{currData.CodArticolo}";
+ string setPzCommVal = $"{qtyNew}";
+ string setCommVal = $"ODL{newOdl}";
+ if (!string.IsNullOrEmpty(keyRichiesta))
+ {
+ setCommVal = $"{keyRichiesta} ODL{newOdl}";
+ }
+ try
+ {
+ // invio task caricamento dati ODL
+ Dictionary updDict = new Dictionary();
+ updDict.Add(taskType.setArt, setArtVal);
+ updDict.Add(taskType.setComm, setCommVal);
+ updDict.Add(taskType.setPzComm, setPzCommVal);
+#if false
+ addTask4Machine(idxMacchina, taskType.setArt, setArtVal);
+ addTask4Machine(idxMacchina, taskType.setComm, setCommVal);
+ addTask4Machine(idxMacchina, taskType.setPzComm, setPzCommVal);
+
+ updateMachineParameter(idxMacchina, "setArt", setArtVal);
+ updateMachineParameter(idxMacchina, "setComm", setCommVal);
+ updateMachineParameter(idxMacchina, "setPzComm", setPzCommVal);
+#endif
+ // recupero set attuale parametri
+ var currMachPar = await MachineParamListAsync(idxMacchina);
+ List list2upd = new();
+ // aggiorno i valori interessati tra quelli nel dizionario
+ foreach (var item in updDict)
+ {
+ var cRec = currMachPar.FirstOrDefault(x => x.uid == $"{item.Key}");
+ if (cRec != null)
+ {
+ list2upd.Add(cRec);
+ }
+ }
+ // aggiungo task di setParameters x la commessa...
+ updDict.Add(taskType.setParameter, setCommVal);
+ // salvo
+ await AddTask4MacListAsync(idxMacchina, updDict);
+ await MachineParamUpsertAsync(idxMacchina, list2upd);
+ }
+ catch
+ { }
+ // chiamo refresh MSE
+ await IocDbController.RecalcMseAsync(idxMacchina, 0);
+ // resetto stato macchina...
+ var kStatoMacc = $"{Utils.redisStatoMacch}:{idxMacchina}";
+ await redisDb.KeyDeleteAsync(kStatoMacc);
+ answ = "OK";
+ Log.Info($"Effettuato reset e ricalcoli x split ODL per macchina {idxMacchina}");
+ // se è una master richiamo fix x child...
+ if (isMachMaster)
+ {
+ Dictionary updDict = new Dictionary();
+ string ts = "";
+ string outData = "";
+ await IocDbController.OdlFixMachineSlaveAsync(idxMacchina, 30, 1);
+ foreach (var machine in slaveList)
+ {
+ // invio chiusura attrezzaggio
+ ts = string.Format("{0:yyMMdd}T{0:HHmmss.fff}Z", DateTime.Now);
+ outData = $"TS:{ts}|MATR:{matrOpr}|ODL:{newOdl}";
+
+ updDict.Clear();
+ updDict.Add(taskType.setArt, setArtVal);
+ updDict.Add(taskType.setComm, setCommVal);
+ updDict.Add(taskType.setPzComm, setPzCommVal);
+
+#if false
+ addTask4Machine(machine.IdxMacchinaSlave, taskType.fixStopSetup, outData);
+ addTask4Machine(machine.IdxMacchinaSlave, taskType.forceResetPzCount, outData);
+ // invio task caricamento dati ODL
+ addTask4Machine(machine.IdxMacchinaSlave, taskType.setArt, setArtVal);
+ addTask4Machine(machine.IdxMacchinaSlave, taskType.setComm, setCommVal);
+ addTask4Machine(machine.IdxMacchinaSlave, taskType.setPzComm, setPzCommVal);
+
+ updateMachineParameter(machine.IdxMacchinaSlave, "setArt", setArtVal);
+ updateMachineParameter(machine.IdxMacchinaSlave, "setComm", setCommVal);
+ updateMachineParameter(machine.IdxMacchinaSlave, "setPzComm", setPzCommVal);
+#endif
+
+ // recupero set attuale parametri
+ var currMachPar = await MachineParamListAsync(machine.IdxMacchinaSlave);
+ List list2upd = new();
+ // aggiorno i valori interessati tra quelli nel dizionario
+ foreach (var item in updDict)
+ {
+ var cRec = currMachPar.FirstOrDefault(x => x.uid == $"{item.Key}");
+ if (cRec != null)
+ {
+ list2upd.Add(cRec);
+ }
+ }
+ // aggiungo task di setParameters x la commessa...
+ updDict.Add(taskType.fixStopSetup, outData);
+ updDict.Add(taskType.forceResetPzCount, outData);
+ updDict.Add(taskType.setParameter, setCommVal);
+ // salvo
+ await AddTask4MacListAsync(machine.IdxMacchinaSlave, updDict);
+ await MachineParamUpsertAsync(machine.IdxMacchinaSlave, list2upd);
+ }
+ }
+ }
+ }
+ catch (Exception exc)
+ {
+ Log.Error($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}");
+ }
+ }
+ return answ;
+ }
+
+ public string CalcRecipe(RecipeModel currRecipe)
+ {
+ return mongoController.CalcRecipe(currRecipe);
+ }
+
+ ///
+ /// controlla se da il segnale di "microstato" deriva un evento da generare - modalità OFFLINE
+ ///
+ /// idx macchina
+ /// valOut ingresso
+ /// data-ora evento (server)
+ /// sequenza dati inviati
+ /// dati macchina in cache (opzionale, se null fa lookup)
+ ///
+ public async Task CheckMicroStatoAsync(string idxMacchina, string valore, DateTime dtEve, string contatore, Dictionary? datiMaccCache = null)
+ {
+ // recupero SE IMPIEGATO REDIS i valori del Dictionary della macchina...
+ Dictionary datiMacc = datiMaccCache ?? await mDatiMacchineAsync(idxMacchina);
+
+ // processing
+ inputComandoMapo answ = new inputComandoMapo();
+
+ // SE no trovassi verifico se esista la macchina altrimenti la creo... REDIS compliant
+ if (!datiMacc.ContainsKey(idxMacchina))
+ {
+ await verificaIdxMacchinaAsync(idxMacchina);
+ }
+
+ // continuo processing...
+ string CodArticolo = datiMacc["CodArticolo"];
+ if (string.IsNullOrEmpty(CodArticolo))
+ {
+ var allDatiMacch = await IocDbController.DatiMacchineGetAllAsync();
+ var recMacc = allDatiMacch.FirstOrDefault(x => x.IdxMacchina == idxMacchina);
+ if (recMacc != null)
+ {
+ CodArticolo = recMacc.CodArticoloA;
+ }
+ }
+ // preparo gestione val ingresso
+ int? valINT = 0;
+ int idxTipoEv = 0;
+ int next_idxMS = 0;
+ try
+ {
+ valINT = int.Parse(valore, NumberStyles.HexNumber);
+ int idxFamIn = Convert.ToInt32(datiMacc["IdxFamIn"]);
+ int idxMicroStato = Convert.ToInt32(datiMacc["IdxMicroStato"]);
+ int valIOB = Convert.ToInt32(valINT);
+ next_idxMS = idxMicroStato;
+ // recupero singolo valOut (stringa) x chiave
+ string todoSMI = await ValoreSmiAsync(idxFamIn, idxMicroStato, valIOB);
+ // solo se ho trovato un risultato nella tab SMI della famiglia macchina...
+ if (!string.IsNullOrEmpty(todoSMI) && todoSMI.Contains("_"))
+ {
+ // splitto e salvo valori OUT...
+ string[] valori = todoSMI.Split('_');
+ idxTipoEv = Convert.ToInt32(valori[0]);
+ next_idxMS = Convert.ToInt32(valori[1]);
+ }
+ }
+ catch (Exception exc)
+ {
+ Log.Error($"[ChkMiSt_5a] - - Eccezione in recupero riga Trans ingressi | idxMacchina {idxMacchina} | valINT {valINT}:{Environment.NewLine}{exc}", Environment.NewLine, exc, valINT, idxMacchina);
+ }
+
+ // effettuo update vari SU DB!!!
+ MicroStatoMacchinaModel newRecMsm = new MicroStatoMacchinaModel()
+ {
+ IdxMacchina = idxMacchina,
+ IdxMicroStato = next_idxMS,
+ InizioStato = dtEve,
+ Value = valore
+ };
+ if (idxTipoEv > 0)
+ {
+ // preparo record
+ string valEsteso = string.Format("[{0}] {1}", contatore.PadLeft(3, '0'), valore);
+ // creo evento
+ EventListModel newRecEv = new EventListModel()
+ {
+ CodArticolo = CodArticolo,
+ IdxMacchina = idxMacchina,
+ IdxTipo = idxTipoEv,
+ InizioStato = dtEve,
+ MatrOpr = 0,
+ pallet = "-",
+ Value = valEsteso
+ };
+ // salva e processa evento + microstato
+ answ = await scriviRigaEventoAsync(newRecMsm, newRecEv);
+ }
+ else
+ {
+ if (useFactory)
+ {
+ await using var scope = _scopeFactory.CreateAsyncScope();
+ var iocService = scope.ServiceProvider.GetRequiredService();
+ // solo microstato
+ await iocService.MicroStatoMacchinaUpsertAsync(newRecMsm);
+ }
+ else
+ {
+ // solo microstato
+ await IocDbController.MicroStatoMacchinaUpsertAsync(newRecMsm);
+ }
+ }
+ return answ;
+ }
+
+ public async Task> ConfigGetAllAsync()
+ {
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ List? result = new List();
+ // cerco in redis...
+ RedisValue rawData = await redisDb.StringGetAsync(Utils.redisConfKey);
+ if (!string.IsNullOrEmpty($"{rawData}"))
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"ConfigGetAllAsync Read from REDIS: {ts.TotalMilliseconds}ms");
+ }
+ else
+ {
+ result = await IocDbController.ConfigGetAllAsync();
+ //result = await Task.FromResult(SpecDbController.ConfigGetAllAsync());
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ await redisDb.StringSetAsync(Utils.redisConfKey, rawData, getRandTOut(redisLongTimeCache));
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"ConfigGetAllAsync Read from DB: {ts.TotalMilliseconds}ms");
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ return result;
+ }
+
+ ///
+ /// Reset dati cache config
+ ///
+ ///
+ public async Task ConfigResetCache()
+ {
+ await redisDb.StringSetAsync(Utils.redisConfKey, "");
+ }
+
+ ///
+ /// Update chiave config
+ ///
+ ///
+ public async Task ConfigUpdate(ConfigModel updRec)
+ {
+ return await Task.FromResult(SpecDbController.ConfigUpdate(updRec));
+ }
+
+ ///
+ /// Elenco completo valori DatiMacchine
+ ///
+ ///
+ public async Task> DatiMacchineGetAll()
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisBaseAddr}:TabDatiMacchine:ALL";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.DatiMacchineGetAll());
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"DatiMacchineGetAll | Read from {readType}: {ts.TotalMilliseconds}ms");
+ 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 valOut 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
+ ///
+ public void Dispose()
+ {
+ // Clear database controller
+ SpecDbController.Dispose();
+ mongoController.Dispose();
+ redisConn.Dispose();
+ }
+
+ ///
+ /// Restituisce l'elenco delle date dei dossier x una macchina (se presenti) Impiegata anche
+ /// cache redis
+ ///
+ ///
+ ///
+ public async Task> DossierLastByMachAsync(string idxMacchina)
+ {
+ List result = new List();
+
+ var currKey = $"{Utils.redisDossByMacLast}:{idxMacchina}";
+ RedisValue rawData = await redisDb.StringGetAsync(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}") ?? new();
+ }
+ else
+ {
+ result = await IocDbController.DossGetLastByMaccAsync(idxMacchina);
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ return result;
+ }
+
+ ///
+ /// Eliminazione di un dossier
+ ///
+ /// record dossier da eliminare
+ ///
+ public async Task DossiersDeleteRecord(DossierModel selRecord)
+ {
+ bool result = false;
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ result = await SpecDbController.DossiersDeleteRecord(selRecord);
+ // elimino cache redis...
+ RedisValue pattern = new RedisValue($"{Utils.redisDossByMac}:*");
+ bool answ = await RedisFlushPatternAsync(pattern);
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"DossiersDeleteRecord | IdxMacchina {selRecord.IdxMacchina} | DtRif {selRecord.DtRif} | IdxODL {selRecord.IdxODL} | {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Elenco ultimi n record DOssiers (che contengono ad esempio "salvataggi" di FLuxLog) dato
+ /// macchina (ordinato x data registrazione)
+ ///
+ /// * = tutte, altrimenti solo x una data macchina
+ /// Data minima per estrazione records
+ /// Data Massima per estrazione records
+ /// Num Max records da recuperare
+ ///
+ public async Task> DossiersGetLastFilt(string IdxMacchina, string CodArticolo, DateTime DtStart, DateTime DtEnd, int MaxRec)
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisDossByMac}:{IdxMacchina}:{CodArticolo}:{DtStart:yyyyMMddHHmm}:{DtEnd:yyyyMMddHHmm}:{MaxRec}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = await redisDb.StringGetAsync(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await SpecDbController.DossiersGetLastFiltAsync(IdxMacchina, CodArticolo, DtStart, DtEnd, MaxRec);
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache / 5));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"DossiersGetLastFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Inserimento nuovo record dossier
+ ///
+ ///
+ ///
+ public async Task DossiersInsert(DossierModel currDoss)
+ {
+ // aggiorno record sul DB
+ bool answ = await SpecDbController.DossiersInsert(currDoss);
+
+ return answ;
+ }
+
+ ///
+ /// Effettua salvataggio snapshot parametri (con stored) + svuota eventuale cache redis
+ ///
+ /// macchina
+ /// NUm massimo secondi per recuperare dati correnti
+ /// DataOra riferimento x cui prendere valori antecedenti
+ ///
+ public async Task DossiersTakeParamsSnapshotLast(string IdxMacchina, DateTime dtMin, DateTime dtMax)
+ {
+ bool answ = false;
+ await Task.Delay(1);
+ Log.Info($"Richiesta snapshot per macchina {IdxMacchina} | periodo {dtMin} --> {dtMax}");
+ // chiamo stored x salvare parametri
+ SpecDbController.DossiersTakeParamsSnapshotLast(IdxMacchina, dtMin, dtMax);
+ // elimino cache redis...
+ RedisValue pattern = new RedisValue($"{Utils.redisDossByMac}:*");
+ answ = await RedisFlushPatternAsync(pattern);
+ Log.Info($"Svuotata cache dossier | {pattern}");
+ return answ;
+ }
+
+ ///
+ /// Update valOut dossier
+ ///
+ ///
+ ///
+ public async Task DossiersUpdateValore(DossierModel currDoss)
+ {
+ // aggiorno record sul DB
+ bool answ = await SpecDbController.DossiersUpdateValore(currDoss);
+
+ return answ;
+ }
+
+ ///
+ /// Restitusice elenco aziende
+ ///
+ ///
+ public Task> ElencoAziende()
+ {
+ return Task.FromResult(SpecDbController.AnagGruppiAziende());
+ }
+
+ ///
+ /// Restitusice elenco fasi
+ ///
+ ///
+ public Task> ElencoGruppiFase()
+ {
+ List result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisAnagGruppi}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ var rawResult = JsonConvert.DeserializeObject>($"{rawData}");
+ if (rawResult != null)
+ {
+ result = rawResult;
+ }
+ readType = "REDIS";
+ }
+ else
+ {
+ result = SpecDbController.AnagGruppiFase();
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache / 5));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"ElencoGruppiFase | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return Task.FromResult(result);
+ }
+
+ public Task> ElencoLink()
+ {
+ return Task.FromResult(SpecDbController.ElencoLink());
+ }
+
+ ///
+ /// Aggiunta record EventList
+ ///
+ ///
+ ///
+ public async Task EvListInsert(EventListModel newRec)
+ {
+ return await SpecDbController.EvListInsert(newRec);
+ }
+
+ ///
+ /// Imposta in redis la scadenza della pagina x il reload
+ ///
+ ///
+ ///
+ public DateTime ExpiryReloadParamGet()
+ {
+ DateTime dtRif = DateTime.Now;
+ string currKey = $"{Utils.redisParamPageExp}";
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ dtRif = JsonConvert.DeserializeObject($"{rawData}");
+ }
+ return dtRif;
+ }
+
+ ///
+ /// Imposta in redis la scadenza della pagina x il reload
+ ///
+ ///
+ ///
+ public bool ExpiryReloadParamSet(DateTime expTime)
+ {
+ bool fatto = false;
+ string currKey = $"{Utils.redisParamPageExp}";
+ string rawData = JsonConvert.SerializeObject(expTime);
+ fatto = redisDb.StringSet(currKey, rawData);
+ 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
+ .Select(x => x.DtRif)
+ .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 tryGetConfigAsync("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);
+ RedisValue pattern = Utils.RedValue("*");
+ bool answ = await RedisFlushPatternAsync(pattern);
+ // rileggo vocabolario.,..
+ ObjVocabolario = VocabolarioGetAll();
+ return answ;
+ }
+
+ public async Task FlushRedisKey(string redKey)
+ {
+ await Task.Delay(1);
+ RedisValue pattern = Utils.RedValue(redKey);
+ bool answ = await RedisFlushPatternAsync(pattern);
+ return answ;
+ }
+
+ public List FluxLogDtoGetByFlux(string Valore)
+ {
+ List answ = new List();
+ DossierFluxLogDTO? result = JsonConvert.DeserializeObject(Valore);
+ if (result != null)
+ {
+ if (result.ODL != null)
+ {
+ answ = result
+ .ODL
+ .OrderBy(x => x.CodFlux)
+ .ToList();
+ // inizializzo SE necessario
+ foreach (var item in answ)
+ {
+ item.ValoreEdit = String.IsNullOrEmpty(item.ValoreEdit) ? item.Valore : item.ValoreEdit;
+ }
+ }
+ }
+ return answ;
+ }
+
+ ///
+ /// Elenco ultimi n record flux log dato macchina e flusso (ordinato x data registrazione)
+ ///
+ /// Data massima x eventi
+ /// Data minima x eventi
+ /// * = tutte, altrimenti solo x una data macchina
+ /// *=tutti, altrimenti solo selezionato
+ /// numero massimo record da restituire
+ ///
+ public async Task> FluxLogGetLastFilt(DateTime DtMax, DateTime DtMin, string IdxMacchina, string CodFlux, int MaxRec, double redisCacheSec)
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisFluxLogFilt}:{IdxMacchina}:{CodFlux}:{MaxRec}:{DtMax:yyyyMMddHHmm}:{DtMin:yyyyMMddHHmm}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.FluxLogGetLastFilt(DtMax, DtMin, IdxMacchina, CodFlux, MaxRec));
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ if (string.IsNullOrEmpty(canCacheParametri))
+ {
+ canCacheParametri = await tryGetConfigAsync("SPEC_ParametriEnableRedisCache");
+ }
+ if (canCacheParametri != "false")
+ {
+ redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisCacheSec));
+ }
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"FluxLogGetLastFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Restituisce il valOut dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza
+ /// ODL NO invio/gestione ODL)
+ ///
+ ///
+ ///
+ public async Task GetCurrOdlAsync(string idxMacchina)
+ {
+ string result = "";
+ string currKey = $"{Utils.redisOdlCurrByMac}:{idxMacchina}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = $"{rawData}";
+ }
+ else
+ {
+ result = await GetCurrOdlByProdAsync(idxMacchina);
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ return result;
+ }
+
+ ///
+ /// Restituisce il valOut dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza
+ /// ODL NO invio/gestione ODL)
+ ///
+ ///
+ /// indica se forzare lettura da db (true) o meno
+ ///
+ public async Task GetCurrOdlAsync(string idxMacchina, bool forceDb)
+ {
+ string answ = "";
+ // se ho forceDB leggo dai dati prod...
+ if (forceDb)
+ {
+ var datiProd = await StatoProdMacchinaAsync(idxMacchina, DateTime.Now, true);
+ if (datiProd != null)
+ {
+ answ = datiProd.IdxOdl.ToString();
+ }
+ }
+ else
+ {
+ answ = await GetCurrOdlAsync(idxMacchina);
+ }
+ return answ;
+ }
+
+ ///
+ /// Restituisce il valOut dell'ultimo ODL
+ ///
+ ///
+ ///
+ public async Task GetLastOdlAsync(string idxMacchina)
+ {
+ ODLExpModel result = new ODLExpModel();
+ string currKey = $"{Utils.redisOdlLastByMac}:{idxMacchina}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject($"{rawData}") ?? new();
+ }
+ else
+ {
+ result = await IocDbController.OdlLastByMaccAsync(idxMacchina);
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ return result;
+ }
+
+ ///
+ /// Effettua calcolo data-ora di riferimento per il server a partire da
+ ///
+ ///
+ ///
+ ///
+ public DateTime GetSrvDtEvent(string dtEve, string dtCurr)
+ {
+ DateTime dataOraEvento = DateTime.Now;
+ // 2017.09.14 trimmo eventualmente lo zero finale dalle date SE supera i millisecondi...
+ dtEve = dtEve.Length > 17 ? dtEve.Substring(0, 17) : dtEve;
+ dtCurr = dtCurr.Length > 17 ? dtCurr.Substring(0, 17) : dtCurr;
+ DateTime dtEvento, dtCorrente;
+ // controllo: se ho valori dt x evento e orario DIVERSI per acquisitore IOB calcolo
+ // dataOraEvento corretto
+ if (dtEve != dtCurr)
+ {
+ Int64 delta = 0;
+ try
+ {
+ // se ho meno decimali x evento rispetto dtCorrente...
+ if (dtEve.Length < dtCurr.Length)
+ {
+ dtEve = dtEve.PadRight(dtCurr.Length, '0');
+ }
+ delta = Convert.ToInt64(dtCurr) - Convert.ToInt64(dtEve);
+ // se meno di 60'000 ms ...
+ if (delta < 59999)
+ {
+ dataOraEvento = dataOraEvento.AddMilliseconds(-delta);
+ }
+ else
+ {
+ // in questo caso elimino i MS dalle stringhe e converto i datetime....
+ CultureInfo provider = CultureInfo.InvariantCulture;
+ string format = "yyyyMMddHHmmssfff";
+ dtEvento = DateTime.ParseExact(dtEve, format, provider);
+ dtCorrente = DateTime.ParseExact(dtCurr, format, provider);
+ TimeSpan deltaTS = dtCorrente.Subtract(dtEvento);
+ dataOraEvento = dataOraEvento.Add(-deltaTS);
+ }
+ }
+ catch (Exception exc)
+ {
+ Log.Error($"getSrvDtEvent | Errore calcolo ora corrente da IOB remoto | dtEve: {dtEve} | dtCurr: {dtCurr}{Environment.NewLine}" +
+ $"{exc}");
+ }
+ }
+
+ return dataOraEvento;
+ }
+
+ ///
+ /// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
+ ///
+ ///
+ ///
+ public async Task> GetTask2ExeMacchinaAsync(string idxMacchina)
+ {
+ var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
+ return await RedisGetHashDictAsync(currHash);
+ }
+
+ ///
+ /// Init ricetta
+ ///
+ ///
+ ///
+ ///
+ ///
+ public RecipeModel InitRecipe(string confPath, int idxPODL, Dictionary CalcArgs)
+ {
+ return mongoController.InitRecipe(confPath, idxPODL, CalcArgs);
+ }
+
+ ///
+ /// Restituisce il valOut booleano se la macchina sia abilitata all'input
+ ///
+ ///
+ ///
+ public async Task IobInsEnabAsync(string idxMacchina)
+ {
+ var key = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
+
+ string? val = await redisDb.HashGetAsync(key, "insEnabled");
+
+ if (val == null)
+ {
+ var data = await ResetDatiMacchinaAsync(idxMacchina);
+ data.TryGetValue("insEnabled", out val);
+ }
+
+ return val != null && (val == "1" || val.ToLower() == "true");
+ }
+
+ ///
+ /// Restituisce il valOut booleano se la macchina sia master
+ ///
+ ///
+ ///
+ public async Task IobIsMasterAsync(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, "Master");
+
+ // 2. Se non c'è in cache, carichiamo/resettiamo tutto
+ if (val == null)
+ {
+ //var data = ResetDatiMacchina(idxMacchina);
+ var data = await ResetDatiMacchinaAsync(idxMacchina);
+ data.TryGetValue("Master", out val);
+ }
+
+ // 3. Parsing sicuro
+ return val != null && (val == "1" || val.ToLower() == "true");
+ }
+
+ ///
+ /// Restituisce il valOut booleano se la macchina sia abilitata all'inserimento COMPLETO nel
+ /// Signal Log
+ ///
+ ///
+ ///
+ public async Task IobSLogEnabAsync(string idxMacchina)
+ {
+ bool answ = false;
+ // ORA recupero da memoria redis...
+ try
+ {
+ var currHash = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
+ RedisValue rawData = await redisDb.HashGetAsync(currHash, (RedisValue)"sLogEnabled");
+ // se è vuoto... leggo da DB e popolo!
+ if (!rawData.HasValue)
+ {
+ await ResetDatiMacchinaAsync(idxMacchina);
+ // riprovo
+ rawData = await redisDb.HashGetAsync(currHash, (RedisValue)"sLogEnabled");
+ }
+
+ // provo conversione
+ bool.TryParse($"{rawData}", out answ);
+ }
+ catch (Exception exc)
+ {
+ Log.Error($"Errore IobSLogEnabAsync | idxMacchina {idxMacchina}:{Environment.NewLine}{exc}");
+ }
+ return answ;
+ }
+
+ ///
+ ///
+ /// idxMacc odl da cercare
+ ///
+ public async Task> ListGiacenze(int IdxOdl)
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisGiacenzaList}:{IdxOdl}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.ListGiacenze(IdxOdl));
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"ListGiacenze | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ public async Task> ListValuesFilt(string tabName, string fieldName)
+ {
+ List resultList = new List();
+ string tag = "";
+ tag += string.IsNullOrEmpty(tabName) ? "" : $"{tabName}:";
+ tag += string.IsNullOrEmpty(fieldName) ? "" : $"{fieldName}:";
+ var currKey = $"{Utils.redisConfFlux}:{tag}";
+ RedisValue rawData = await redisDb.StringGetAsync(currKey);
+ if (rawData.HasValue)
+ {
+ resultList = JsonConvert.DeserializeObject>($"{rawData}") ?? new();
+ }
+ else
+ {
+ resultList = await IocDbController.ListValuesFiltAsync(tabName, fieldName);
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(resultList);
+ await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (resultList == null)
+ {
+ resultList = new();
+ }
+ return resultList;
+ }
+
+ ///
+ /// Elenco completo valori Macchine 2 Slave
+ ///
+ ///
+ public async Task> Macchine2SlaveGetAllAsync()
+ {
+ List? result = new List();
+ string currKey = $"{Utils.redisBaseAddr}:M2STab";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = await redisDb.StringGetAsync(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ }
+ else
+ {
+ if (useFactory)
+ {
+ await using var scope = _scopeFactory.CreateAsyncScope();
+ var mtcService = scope.ServiceProvider.GetRequiredService();
+ result = await mtcService.Macchine2SlaveAsync();
+ }
+ else
+ {
+ result = await IocDbController.Macchine2SlaveAsync();
+ }
+
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ return result;
+ }
+
+ ///
+ /// Elenco di tutte le macchine gestite
+ ///
+ ///
+ ///
+ public async Task> MacchineGetFilt(string codGruppo)
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string keyGrp = codGruppo != "*" ? codGruppo : "ALL";
+ string currKey = $"{Utils.redisMacList}:{keyGrp}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.MacchineGetFilt(codGruppo));
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"MacchineGetAll | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Verifica se la macchina abbia un codice PATH ricette associato
+ ///
+ ///
+ ///
+ public async Task MacchineRecipeArchive(string idxMacchina)
+ {
+ string? result = "";
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisMacRecipePath}:{idxMacchina}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ //recupero elenco macchine...
+ var machineList = await MacchineGetFilt("*");
+ var currMach = machineList.Where(x => x.IdxMacchina == idxMacchina).FirstOrDefault();
+ result = currMach != null ? currMach.RecipeArchivePath : null;
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"MacchineRecipeArchive | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result ?? "";
+ }
+
+ ///
+ /// Verifica se la macchina abbia un codice CONF ricetta associato
+ ///
+ ///
+ ///
+ public async Task MacchineRecipeConf(string idxMacchina)
+ {
+ string? result = "";
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisMacRecipeConf}:{idxMacchina}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ //recupero elenco macchine...
+ var machineList = await MacchineGetFilt("*");
+ var currMach = machineList.Where(x => x.IdxMacchina == idxMacchina).FirstOrDefault();
+ result = currMach != null ? currMach.RecipePath : null;
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"MacchineRecipeConf | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result ?? "";
+ }
+
+ ///
+ /// Elenco idxMacc Macchine che abbiano dati FLuxLog, nel periodo indicato
+ ///
+ ///
+ ///
+ ///
+ public async Task> MacchineWithFlux(DateTime dtStart, DateTime dtEnd)
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisMacByFlux}:{dtStart:yyyyMMddHHmm}:{dtEnd:yyyyMMddHHmm}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await SpecDbController.MacchineWithFlux(dtStart, dtEnd);
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"MacchineWithFlux | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Lista parametri correnti (ObjItemDTO) della macchina (ex getCurrObjItems)
+ ///
+ ///
+ ///
+ public List MachineParamList(string idxMacchina)
+ {
+ // setup parametri costanti
+ string source = "NA";
+ Stopwatch sw = new Stopwatch();
+ sw.Start();
+ List? result = new List();
+ // cerco in _redisConn...
+ var currKey = Utils.RedKeyCurrObjItems(idxMacchina, MpIoNS);
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue && rawData.Length() > 2)
+ {
+ var rawVal = JsonConvert.DeserializeObject>($"{rawData}");
+ // ordino!
+ result = rawVal
+ .OrderBy(x => x.displOrdinal)
+ .ThenBy(x => x.description)
+ .ToList();
+ source = "REDIS";
+ }
+ if (result == null)
+ {
+ result = new List();
+ source = "NONE";
+ }
+ sw.Stop();
+ Log.Debug($"MachineParamList | {source} | {sw.Elapsed.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Lista parametri correnti (ObjItemDTO) della macchina (ex getCurrObjItems)
+ ///
+ ///
+ ///
+ public async Task> MachineParamListAsync(string idxMacchina)
+ {
+ // setup parametri costanti
+ string source = "NA";
+ Stopwatch sw = new Stopwatch();
+ sw.Start();
+ List? result = new List();
+ // cerco in _redisConn...
+ var currKey = Utils.RedKeyCurrObjItems(idxMacchina, MpIoNS);
+ RedisValue rawData = await redisDb.StringGetAsync(currKey);
+ if (rawData.HasValue && rawData.Length() > 2)
+ {
+ var rawVal = JsonConvert.DeserializeObject>($"{rawData}");
+ // ordino!
+ result = rawVal
+ .OrderBy(x => x.displOrdinal)
+ .ThenBy(x => x.description)
+ .ToList();
+ source = "REDIS";
+ }
+ if (result == null)
+ {
+ result = new List();
+ source = "NONE";
+ }
+ sw.Stop();
+ Log.Debug($"MachineParamListAsync | {source} | {sw.Elapsed.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Lista parametri correnti che necessitano di write della macchina (ex getCurrObjItems)
+ ///
+ ///
+ ///
+ public async Task> MachineParamListPendingWriteAsync(string idxMacchina)
+ {
+ List? result = new List();
+ // recupero tutti i parametri
+ var allData = await MachineParamListAsync(idxMacchina);
+ result = allData.Where(x => x.writable && !string.IsNullOrEmpty(x.reqValue)).ToList();
+ return result;
+ }
+
+ ///
+ /// Esegue aggiornamento MachineParamList (ex CurrObjItems) Async
+ ///
+ ///
+ ///
+ ///
+ public async Task MachineParamListSetAsync(string idxMacchina, List currData)
+ {
+ string serVal = JsonConvert.SerializeObject(currData);
+ var currKey = Utils.RedKeyCurrObjItems(idxMacchina, MpIoNS);
+ bool fatto = await redisDb.StringSetAsync(currKey, serVal);
+ return fatto;
+ }
+
+ ///
+ /// Effettua UPSERT elenco parametri correnti x IOB (se c'è UPDATE, se manca ADD)
+ ///
+ ///
+ ///
+ ///
+ public async Task MachineParamUpsertAsync(string idxMacchina, List innovations)
+ {
+ bool answ = false;
+ if (innovations != null)
+ {
+ Log.Info($"upsertCurrObjItems | idxMacchina: {idxMacchina} | {innovations.Count} innovations");
+ // leggo i valori attuali...
+ List actValues = await MachineParamListAsync(idxMacchina);
+ // per ogni valOut passatomi faccio insert o update rispetto elenco valori correnti
+ // in REDIS
+ foreach (var item in actValues)
+ {
+ // cerco nelle innovazioni SE CI SIA il valOut...
+ var trovato = innovations.Find(obj => obj.uid == item.uid);
+ // se non trovato nelle innovazioni...
+ if (trovato == null)
+ {
+ // lo ri-aggiungo x non perderlo
+ innovations.Add(item);
+ // in base a value (value == null) uso debug/info
+ if (string.IsNullOrEmpty(item.value))
+ {
+ Log.Debug($"idxMacchina: {idxMacchina} | innovations | add | item.uid: {item.uid} | item.value: {item.value}");
+ }
+ else
+ {
+ Log.Info($"idxMacchina: {idxMacchina} | innovations | add | item.uid: {item.uid} | item.value: {item.value}");
+ }
+ }
+ // altrimenti aggiorno campo (non trasmesso) name e tengo il resto...
+ else
+ {
+ trovato.name = item.name;
+ Log.Debug($"idxMacchina: {idxMacchina} | innovations | update | item.uid: {item.uid} | item.value: {item.value} --> {trovato.value} ");
+ }
+ }
+ // serializzo e salvo
+ answ = await MachineParamListSetAsync(idxMacchina, innovations);
+ }
+ 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 = await ResetDatiMacchinaAsync(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
+ ///
+ ///
+ ///
+ public Dictionary mOptParMacchina(string idxMacchina)
+ {
+ // hard coded dimensione vettore DatiMacchine
+ Dictionary answ = new Dictionary();
+ // ORA recupero da memoria redis...
+ RedisKey currHash = Utils.RedKeyOptPar(idxMacchina, MpIoNS);
+ answ = RedisGetHashDict(currHash);
+ return answ;
+ }
+
+ ///
+ /// Restitusice elenco KVP dei TASK SALVATI (da passare a IOB-WIN) per l'impianto indicato
+ ///
+ ///
+ ///
+ public Dictionary mSavedTaskMacchina(string idxMacchina)
+ {
+ // hard coded dimensione vettore DatiMacchine
+ Dictionary answ = new Dictionary();
+ // ORA recupero da memoria redis...
+ try
+ {
+ RedisKey currHash = Utils.RedKeySavedTask2ExeMacc(idxMacchina);
+ answ = RedisGetHashDict(currHash);
+ }
+ catch (Exception exc)
+ {
+ Log.Info($"Errore in recupero dati SAVED TASK x Redis mSavedTaskMacchina | idxMacchina {idxMacchina}{Environment.NewLine}{exc}");
+ }
+ 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 (async) per evitare blocchi quando chiamato da metodi asincroni
+ ///
+ ///
+ ///
+ public async Task[]> mTabMSMIAsync(string idxMacchina)
+ {
+ KeyValuePair[] answ = new KeyValuePair[1];
+ answ[0] = new KeyValuePair("0", "0");
+ try
+ {
+ var currHash = Utils.RedKeyMsmi(idxMacchina);
+ answ = await RedisGetHashAsync(currHash);
+ if (answ == null || answ.Length == 0)
+ {
+ answ = await resetMSMIAsync(idxMacchina);
+ }
+ }
+ catch (Exception exc)
+ {
+ Log.Error($"Errore in compilazione Tabella Multi State Machine Ingressi x Redis:{Environment.NewLine}{exc}");
+ }
+ return answ;
+ }
+
+ ///
+ /// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
+ ///
+ ///
+ ///
+ public Dictionary mTaskMacchina(string idxMacchina)
+ {
+ // hard coded dimensione vettore DatiMacchine
+ Dictionary answ = new Dictionary();
+ // ORA recupero da memoria redis...
+ try
+ {
+ var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
+ answ = RedisGetHashDict(currHash);
+ }
+ catch (Exception exc)
+ {
+ Log.Error(string.Format("Errore in mTaskMacchina | idxMacchina {2}:{0}{1}", Environment.NewLine, exc, idxMacchina));
+ }
+ return answ;
+ }
+
+ ///
+ /// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
+ ///
+ ///
+ ///
+ public async Task> mTaskMacchinaAsync(string idxMacchina)
+ {
+ // hard coded dimensione vettore DatiMacchine
+ Dictionary answ = new Dictionary();
+ // ORA recupero da memoria redis...
+ var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
+ answ = await RedisGetHashDictAsync(currHash);
+ return answ;
+ }
+
+ ///
+ /// Generazione autoOdl
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task OdlAutoDayGenAsync(string idxMacchina, DateTime dataInizio, DateTime dataFine, string codArticolo)
+ {
+ var result = await IocDbController.OdlAutoDayGenAsync(idxMacchina, dataInizio, dataFine, codArticolo);
+ return result;
+ }
+
+ ///
+ /// Generazione autoOdl
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task OdlAutoDayGenFullAsync(string idxMacchina, DateTime dataInizio, DateTime dataFine, string codArticolo, int? pzPODL, int? pzPallet, string? keyRichiesta, int? tcAssegnato, string? codGruppo, bool flgCreaPODL, bool flgCheckTC)
+ {
+ var result = await IocDbController.OdlAutoDayGenFullAsync(idxMacchina, dataInizio, dataFine, codArticolo, pzPODL, pzPallet, keyRichiesta, tcAssegnato, codGruppo, flgCreaPODL, flgCheckTC);
+ return result;
+ }
+
+ ///
+ /// Elenco ODL dato batch selezionato
+ ///
+ /// Batch richiesto
+ ///
+ public async Task> OdlByBatch(string BatchSel)
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = Utils.redisOdlByBatch;
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.OdlByBatch(BatchSel));
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"OdlByBatch | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// ODL da chiave
+ ///
+ ///
+ ///
+ public ODLExpModel OdlByKey(int IdxOdl)
+ {
+ ODLExpModel? result = new ODLExpModel();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ result = SpecDbController.OdlByKey(IdxOdl);
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"OdlByKey | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Effettua chiusura dell'ODL indicato, andand
+ ///
+ /// idx odl da chiudere
+ /// idx macchina
+ /// matricola operatore
+ /// indica se confermare i pezzi priam di chiudere ODL
+ public async Task ODLClose(int idxOdl, string idxMacchina, int matrOpr, bool confPezzi)
+ {
+ bool fatto = false;
+ await Task.Delay(1);
+ // recupero dati x conf modalità conferma
+ var configData = await ConfigGetAllAsync();
+ if (configData != null)
+ {
+ bool confRett = false;
+ var currRec = configData.FirstOrDefault(x => x.Chiave == "confRett");
+ if (currRec != null)
+ {
+ bool.TryParse(currRec.Valore, out confRett);
+ }
+ int modoConfProd = 0;
+ currRec = configData.FirstOrDefault(x => x.Chiave == "modoConfProd");
+ if (currRec != null)
+ {
+ int.TryParse(currRec.Valore, out modoConfProd);
+ }
+ // chiamo metodo conferma!
+ fatto = await SpecDbController.ODLClose(idxOdl, idxMacchina, matrOpr, confPezzi, confRett, modoConfProd);
+ }
+
+ return fatto;
+ }
+
+ public async Task OdlCurrByMaccAsync(string IdxMacchina)
+ {
+ ODLExpModel result = new();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisOdlList}:Current:{IdxMacchina}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = await redisDb.StringGetAsync(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject($"{rawData}") ?? new();
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await IocDbController.OdlCurrByMaccAsync(IdxMacchina);
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
+ }
+ if (result == null)
+ {
+ result = new();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Trace($"OdlCurrByMaccAsync | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Record ODL da chaive
+ ///
+ ///
+ public async Task OdlGetByKey(int IdxOdl)
+ {
+ await Task.Delay(1);
+ var dbResult = await SpecDbController.OdlGetByKey(IdxOdl);
+ return dbResult;
+ }
+
+ ///
+ /// ODL correnti (tutti)
+ ///
+ ///
+ ///
+ public List OdlGetCurrent()
+ {
+ List? dbResult = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisOdlCurrByMac}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ try
+ {
+ dbResult = JsonConvert.DeserializeObject>($"{rawData}");
+ }
+ catch
+ { }
+ readType = "REDIS";
+ }
+ else
+ {
+ dbResult = SpecDbController.OdlGetCurrent().Select(x => x.IdxMacchina).Distinct().ToList();
+ rawData = JsonConvert.SerializeObject(dbResult);
+ redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(3));
+ }
+ if (dbResult == null)
+ {
+ dbResult = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"OdlGetCurrent | Read from {readType}: {ts.TotalMilliseconds}ms");
+
+ return dbResult;
+ }
+
+ ///
+ /// elenco TUTTI gli ODL
+ ///
+ ///
+ ///
+ public List OdlListAll()
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ result = SpecDbController.OdlListAll();
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"OdlListAll | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Elenco ODL filtrati x stato, articolo, KeyRich (che contiene stato)
+ ///
+ /// Stato ODL: true=in corso/completato
+ /// Cod articolo
+ /// KeyRich (parziale) da cercare (es cod stato x yacht)
+ /// Reparto selezionato
+ /// Macchina selezionata
+ /// Data inizio
+ /// Data fine
+ ///
+ public async Task> OdlListGetFilt(bool inCorso, string codArt, string keyRichPart, string Reparto, string IdxMacchina, DateTime startDate, DateTime endDate)
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisOdlList}:{inCorso}:{codArt}:{keyRichPart}:{Reparto}:{IdxMacchina}:{startDate:yyyyMMdd_HHmmss}:{endDate:yyyyMMdd_HHmmss}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.ListODLFilt(inCorso, codArt, keyRichPart, Reparto, IdxMacchina, startDate, endDate));
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"OdlListGetFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Elenco di tutti i parametri filtrati x macchina
+ ///
+ /// * = tutte, altrimenti solo x una data macchina
+ ///
+ public async Task> ParametriGetFilt(string IdxMacchina)
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisFluxByMac}:{IdxMacchina}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.ParametriGetFilt(IdxMacchina));
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"ParametriGetFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Eliminazione record selezionato
+ ///
+ ///
+ ///
+ public async Task POdlDeleteRecord(PODLExpModel currRec)
+ {
+ var dbResult = await SpecDbController.PODLDeleteRecord(currRec);
+ // elimino cache redis...
+ await POdlFlushCache();
+ await Task.Delay(1);
+ return dbResult;
+ }
+
+ ///
+ /// Avvio fase setup per il record selezionato
+ ///
+ ///
+ ///
+ public async Task POdlDoSetup(PODLExpModel currRec)
+ {
+ var dbResult = await SpecDbController.PODL_startSetup(currRec, 0, 1, 1, "", DateTime.Now);
+ // elimino cache redis...
+ await POdlFlushCache();
+ await Task.Delay(1);
+ return dbResult;
+ }
+
+ ///
+ /// Recupero PODL da chiave
+ ///
+ ///
+ ///
+ public async Task POdlGetByKey(int idxPODL)
+ {
+ PODLModel result = new PODLModel();
+ if (idxPODL != 0)
+ {
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisPOdlByPOdl}:{idxPODL}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ var rawResult = JsonConvert.DeserializeObject($"{rawData}");
+ if (rawResult != null)
+ {
+ result = rawResult;
+ readType = "REDIS";
+ }
+ }
+ else
+ {
+ result = await SpecDbController.PODL_getByKey(idxPODL);
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (result == null)
+ {
+ result = new PODLModel();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Trace($"POdlGetByKey | Read from {readType}: {ts.TotalMilliseconds}ms");
+ }
+ else
+ {
+ Log.Debug("Errore IdxPODL = 0");
+ }
+ return result;
+ }
+
+ public async Task> POdlGetByMaccArtAsync(string idxMacchina, string codArticolo, string codGruppo, bool onlyFree)
+ {
+ List result = new List();
+
+ var currKey = $"{Utils.redisPOdlByMaccArt}:{idxMacchina}";
+ if (!string.IsNullOrEmpty(codArticolo))
+ {
+ currKey += $":A{codArticolo}";
+ }
+ if (!string.IsNullOrEmpty(codGruppo))
+ {
+ currKey += $":G{codGruppo}";
+ }
+ currKey += onlyFree ? $":FREE" : ":ALL";
+ RedisValue rawData = await redisDb.StringGetAsync(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}") ?? new();
+ }
+ else
+ {
+ result = await IocDbController.POdlGetByMaccArtAsync(idxMacchina, codArticolo, codGruppo, onlyFree);
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ return result;
+ }
+
+ ///
+ /// Recupero PODL da IdxODL
+ ///
+ ///
+ ///
+ public PODLModel POdlGetByOdl(int idxODL)
+ {
+ PODLModel result = new PODLModel();
+ if (idxODL != 0)
+ {
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisPOdlByOdl}:{idxODL}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ var rawResult = JsonConvert.DeserializeObject($"{rawData}");
+ if (rawResult != null)
+ {
+ result = rawResult;
+ }
+ readType = "REDIS";
+ }
+ else
+ {
+ result = SpecDbController.PODL_getByOdl(idxODL);
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
+ }
+ if (result == null)
+ {
+ result = new PODLModel();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Trace($"POdlGetByOdl | Read from {readType}: {ts.TotalMilliseconds}ms");
+ }
+ else
+ {
+ Log.Debug("Errore IdxODL = 0");
+ }
+ return result;
+ }
+
+ ///
+ /// Elenco PODL non avviati filtrati x articolo, KeyRich (che contiene stato)
+ ///
+ /// Solo lanciati (1) o ancora disponibili (0)
+ /// KeyRich (parziale) da cercare (es cod stato x yacht)
+ /// Macchina
+ /// Gruppo
+ /// Data inizio
+ /// Data fine
+ ///
+ public async Task> POdlListGetFilt(bool lanciato, string keyRichPart, string idxMacchina, string codGruppo, DateTime startDate, DateTime endDate)
+ {
+ List? result = new List();
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "DB";
+ string currKey = $"{Utils.redisPOdlList}:{codGruppo}:{idxMacchina}:{keyRichPart}:{lanciato}:{startDate:yyyyMMdd_HHmmss}:{endDate:yyyyMMdd_HHmmss}";
+ // cerco in redis dato valOut sel macchina...
+ RedisValue rawData = redisDb.StringGet(currKey);
+ if (rawData.HasValue)
+ {
+ result = JsonConvert.DeserializeObject>($"{rawData}");
+ readType = "REDIS";
+ }
+ else
+ {
+ result = await Task.FromResult(SpecDbController.ListPODLFilt(lanciato, keyRichPart, idxMacchina, codGruppo, startDate, endDate));
+ // serializzo e salvo...
+ rawData = JsonConvert.SerializeObject(result);
+ redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
+ }
+ if (result == null)
+ {
+ result = new List();
+ }
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"POdlListGetFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///
+ /// Aggiornamento record selezionato
+ ///
+ ///
+ ///
+ public async Task POdlUpdateRecord(PODLModel currRec)
+ {
+ var dbResult = await SpecDbController.PODLUpdateRecord(currRec);
+ // elimino cache redis...
+ await POdlFlushCache();
+ return dbResult;
+ }
+
+ ///
+ /// Processa registrazione FL da IOB
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task ProcessFluxLogAsync(string idxMacchina, string flux, string valore, string dtEve, string dtCurr, int contatore, bool disabKA)
+ {
+ // se non vietato...
+ if (!disabKA)
+ {
+ // scrivo keep alive!!! (se necessario, altrimenti è in cache...)
+ await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
+ }
+
+ string answ = "";
+ DateTime dataOraEvento = GetSrvDtEvent(dtEve, dtCurr);
+ // inizio processing vero e proprio INPUT...
+
+ if (string.IsNullOrEmpty(idxMacchina) || string.IsNullOrEmpty(valore))
+ {
+ string errore = "processFluxLog | Errore: parametri macchina/valOut vuoti";
+ Log.Error(errore);
+ answ = errore;
+ }
+ else
+ {
+ FluxLogModel newRec = new FluxLogModel()
+ {
+ IdxMacchina = idxMacchina,
+ dtEvento = dataOraEvento,
+ CodFlux = flux,
+ Valore = valore,
+ Cnt = contatore
+ };
+ await IocDbController.FluxLogInsertAsync(newRec);
+ // 2022.06.06 salvo su redis il valOut ULTIMO del flux x recupero rapido ultimo valOut
+ var currKey = Utils.RedKeyLastFLog(idxMacchina, flux, MpIoNS);
+ // 10 min cache max...
+ await redisDb.StringSetAsync(currKey, valore, TimeSpan.FromMinutes(10));
+ // registro in risposta che è andato tutto bene...
+ answ = "OK";
+ }
+
+ return answ;
+ }
+
+ ///
+ /// Validazione preliminare valori input
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private bool ValidateinputParams(string idxMacchina, string valore, string dtEve, string dtCurr)
+ {
+ bool isValid = false;
+ // preparo stringa valori correnti
+ string currVals = $"idxMacchina: {idxMacchina} | valOut: {valore} | dtEve: {dtEve} | dtCurr:{dtCurr}";
+ if (dtEve == null || dtCurr == null)
+ {
+ Log.Warn($"procInput: null found | {currVals}");
+ }
+ else if (dtEve.Length < 17 || dtCurr.Length < 17)
+ {
+ Log.Info($"procInput: invalid data | {currVals}");
+ }
+ else if (string.IsNullOrEmpty(idxMacchina))
+ {
+ Log.Info($"procInput: missing IdxMacchina | {currVals}");
+ }
+ else if (string.IsNullOrEmpty(valore))
+ {
+ Log.Info($"procInput: missing valOut | {currVals}");
+ }
+ else
+ {
+ isValid = true;
+ }
+ return isValid;
+ }
+
+ ///
+ /// Calcola dataora evento da info dt ricevute
+ ///
+ ///
+ ///
+ ///
+ private DateTime ParseEventTime(string dtEve, string dtCurr)
+ {
+ DateTime dataOraEvento = DateTime.Now;
+
+ // fix formato dataora in ingresso
+ string stdEve = dtFormStd(dtEve);
+ string stdCurr = dtFormStd(dtCurr);
+
+ // 2. Se le stringhe normalizzate coincidono, skip dei calcoli
+ if (stdEve != stdCurr)
+ {
+ // 3. Parsing sicuro
+ if (DateTime.TryParseExact(stdEve, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtEvento) &&
+ DateTime.TryParseExact(stdCurr, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtCorrente))
+ {
+ TimeSpan diff = dtCorrente - dtEvento;
+ double ms = Math.Abs(diff.TotalMilliseconds);
+
+ // 4. Classificazione delta con switch expression (più leggibile e performante)
+ string deltaClass = ms switch
+ {
+ <= 10 => "0-10 ms",
+ <= 100 => "10-100 ms",
+ <= 1000 => "100-1000 ms",
+ <= 10000 => "1-10 sec",
+ _ => "> 10 sec"
+ };
+
+ Log.Debug($"Correzione delta {deltaClass}");
+
+ // 5. Correzione data/ora server: sottrao lo scarto calcolato
+ dataOraEvento = dataOraEvento.Subtract(diff);
+ }
+ else
+ {
+ Log.Error($"Errore parsing date: {stdEve} | {stdCurr}");
+ }
+ }
+ return dataOraEvento;
+ }
+
+ ///
+ /// Processa input da IOB eventualmente registrando i segnali inviati
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task ProcessInputAsync(string idxMacchina, string valore, string dtEve, string dtCurr, string contatore)
+ {
+ string answ = "";
+ if (ValidateinputParams(idxMacchina, valore, dtEve, dtCurr))
+ {
+ DateTime dataOraEvento = ParseEventTime(dtEve, dtCurr);
+
+ // se abilitato registro evento sul DB
+ if (await IobSLogEnabAsync(idxMacchina))
+ {
+ int cntVal = 0;
+ int.TryParse(contatore, out cntVal);
+ await saveSigLogAsync(idxMacchina, valore, dataOraEvento, cntVal);
+ }
+ // continuo col resto
+ try
+ {
+ // scrivo keep alive!!! (se necessario, altrimenti è in cache...)
+ await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
+ // Cache dati macchina per evitare lookup ridondanti
+ Dictionary datiMacc = await mDatiMacchineAsync(idxMacchina);
+ // verifico se sia una macchina MULTI....
+ if (isMulti(idxMacchina, datiMacc))
+ {
+ // inizio preprocessing
+ string newVal = "";
+ // processo OGNI macchina a stati dell'impianto... (KEY:IdxMacchina / IdxMacchina#qualcosa, Val = IdxFamIn)
+ foreach (var item in await mTabMSMIAsync(idxMacchina))
+ {
+ newVal = preProcInput(item.Key, valore, datiMacc);
+ // ora processo e salvo il valOut del microstato...
+ // INTERNAMENTE gestisce i casi DB/REDIS secondo necessità
+ await CheckMicroStatoAsync(item.Key, newVal, dataOraEvento, contatore, datiMacc);
+ }
+ }
+ else
+ {
+ // ora processo e salvo il valOut del microstato... INTERNAMENTE
+ // gestisce i casi DB/REDIS secondo necessità
+ await CheckMicroStatoAsync(idxMacchina, valore, dataOraEvento, contatore, datiMacc);
+ }
+ // forzo RESET dati macchina...
+ await ResetDatiMacchinaAsync(idxMacchina);
+ // registro in risposta che è andato tutto bene...
+ answ = "OK";
+ }
+ catch (Exception exc)
+ {
+ string errore = $"Errore: {Environment.NewLine}{exc}";
+ Log.Error(errore);
+ answ = errore;
+ }
+ }
+ return answ;
+ }
+
+ ///
+ /// Processa registrazione UserLog da IOB
+ ///
+ /// Macchina
+ /// Flusso: DI/RC/RC
+ /// valOut = note/valString
+ /// data evento
+ /// data corrente
+ /// contatore invio
+ /// Matricola Operatore
+ /// label = causale scarto / tagCode
+ /// valNum = esitoOk (0/1) / Quantità di scarto associata
+ ///
+ public async Task ProcessUserLogAsync(string idxMacchina, string flux, string valore, string dtEve, string dtCurr, int contatore, int matrOpr, string label, int valNum)
+ {
+ // scrivo keep alive!!! (se necessario, altrimenti è in cache...)
+ await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
+ // 2017.09.14 trimmo eventualmente lo zero finale dalle date SE supera i millisecondi...
+ dtEve = dtEve.Length > 17 ? dtEve.Substring(0, 17) : dtEve;
+ dtCurr = dtCurr.Length > 17 ? dtCurr.Substring(0, 17) : dtCurr;
+
+ string answ = "";
+ DateTime dataOraEvento = GetSrvDtEvent(dtEve, dtCurr);
+
+ // inizio processing vero e proprio INPUT...
+ if (string.IsNullOrEmpty(idxMacchina) || string.IsNullOrEmpty(flux))
+ {
+ string errore = "processFluxLog | Errore: parametri macchina/flux vuoti";
+ Log.Error(errore);
+ answ = errore;
+ }
+ else
+ {
+ // in base al flusso decido dove e cosa scrivere...
+ switch (flux)
+ {
+ case "DI":
+ RegistroDichiarazioniModel recDich = new RegistroDichiarazioniModel()
+ {
+ IdxMacchina = idxMacchina,
+ DtRec = dataOraEvento,
+ MatrOpr = matrOpr,
+ ValString = valore,
+ TagCode = label
+ };
+ await IocDbController.RegDichiarInsertAsync(recDich);
+ break;
+
+ case "RC":
+ bool esitoOk = valNum != 0;
+ await IocDbController.RegControlliInsertAsync(idxMacchina, matrOpr, esitoOk, valore, dataOraEvento);
+ break;
+
+ case "RS":
+ RegistroScartiModel recSca = new RegistroScartiModel()
+ {
+ IdxMacchina = idxMacchina,
+ DataOra = dataOraEvento,
+ Causale = label,
+ Qta = valNum,
+ Note = valore,
+ MatrOpr = matrOpr
+ };
+ await IocDbController.RegScartiInsertAsync(recSca);
+ break;
+
+ default:
+ break;
+ }
+ // registro in risposta che è andato tutto bene...
+ answ = "OK";
+ }
+ return answ;
+ }
+
+ ///
+ /// Restituisce il contapezzi salvato per la macchina
+ ///
+ ///
+ ///
+ public async Task pzCounter(string idxMacchina)
+ {
+ int answ = -1;
+ try
+ {
+ var currKey = Utils.RedKeyPzCount(idxMacchina, MpIoNS);
+ RedisValue rawData = await redisDb.StringGetAsync(currKey);
+ if (rawData.HasValue)
+ {
+ int.TryParse(rawData, out answ);
+ }
+ else
+ {
+ answ = await PzCounterTcAsync(idxMacchina);
+ // salvo in _redisConn...
+ await redisDb.StringSetAsync(currKey, answ.ToString(), TimeSpan.FromSeconds(1));
+ }
+ }
+ catch (Exception exc)
+ {
+ Log.Error($"Eccezione in pzCounter{Environment.NewLine}{exc}");
+ }
+ return answ;
+ }
+
+ ///
+ /// Restituisce il contapezzi come CONTEGGIO da TCRilevati per la macchina - ASYNC
+ ///
+ ///
+ ///
+ public async Task PzCounterTcAsync(string idxMacchina)
+ {
+ int answ = -1;
+ DateTime dataRif = DateTime.Now;
+ var datiProd = await StatoProdMacchinaAsync(idxMacchina, dataRif);
+ if (datiProd != null)
+ {
+ answ = datiProd.PzTotODL;
+ }
+ return answ;
+ }
+
+ ///
+ /// Ricerca ricetta su MongoDB dato PODL
+ ///
+ ///
+ ///
+ public async Task RecipeGetByPODL(int idxPODL)
+ {
+ RecipeModel? result = null;
+ Stopwatch stopWatch = new Stopwatch();
+ stopWatch.Start();
+ string readType = "MongoDB";
+ result = await mongoController.RecipeGetByPODL(idxPODL);
+ stopWatch.Stop();
+ TimeSpan ts = stopWatch.Elapsed;
+ Log.Debug($"RecipeGetByPODL | Read from {readType}: {ts.TotalMilliseconds}ms");
+ return result;
+ }
+
+ ///