diff --git a/IOB-UT-NEXT/Objects.cs b/IOB-UT-NEXT/Objects.cs index d680955d..c728c8cf 100644 --- a/IOB-UT-NEXT/Objects.cs +++ b/IOB-UT-NEXT/Objects.cs @@ -825,4 +825,17 @@ namespace IOB_UT_NEXT public string valString { get; set; } = ""; } + + + /// + /// Informazioni generiche su batch produzione rilevati + /// + public class ProdBatchData + { + public DateTime dtStart { get; set; } = DateTime.Now; + public DateTime? dtEnd { get; set; } = null; + + public string codArt { get; set; } = ""; + public int numPz { get; set; } = 0; + } } \ No newline at end of file diff --git a/IOB-WIN-NEXT/Iob/Generic.cs b/IOB-WIN-NEXT/Iob/Generic.cs index 123317c1..25fb5bbf 100644 --- a/IOB-WIN-NEXT/Iob/Generic.cs +++ b/IOB-WIN-NEXT/Iob/Generic.cs @@ -1,6 +1,8 @@ using EgwProxy.Ftp; +using EgwProxy.MultiCncLib.OPENcontrol; using IOB_UT_NEXT; using MapoSDK; +using MathNet.Numerics; using MathNet.Numerics.Statistics; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -839,9 +841,9 @@ namespace IOB_WIN_NEXT.Iob } /// - /// URL per AVVIO PODL corrente (metodo GET)... + /// URL per AVVIO di un ODL da PODL indicato (metodo GET)... /// - public string urlOLDStartFromPODL + public string urlOdlStartFromPOdl { get { @@ -857,6 +859,28 @@ namespace IOB_WIN_NEXT.Iob return answ; } } + /// + /// URL per creazione di un PODL da cod art (metodo GET)... + /// + public string urlCreatePOdl + { + get + { + string answ = ""; + try + { + answ = $@"{cIobConf.serverData.TRANSP}://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/forceCreatePOdl/{cIobConf.codIOB}?"; + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlStartPODL"); + } + return answ; + } + } + + + /// /// URL per chiusura PODL --> ODL corrente (metodo GET)... @@ -6530,7 +6554,7 @@ namespace IOB_WIN_NEXT.Iob protected bool trySetupPODL(int idxPODL) { bool fatto = false; - string fullUrl = $"{urlOLDStartFromPODL}{idxPODL}"; + string fullUrl = $"{urlOdlStartFromPOdl}{idxPODL}"; try { // invio chiamata URL x avvio PODL su macchina @@ -6555,7 +6579,7 @@ namespace IOB_WIN_NEXT.Iob { bool fatto = false; //string format = "yyyyMMddHHmmssfff"; - string fullUrl = $"{urlOLDStartFromPODL}{idxPODL}&doConfirm={doConfirm}&dtEve={dtEve:yyyyMMddHHmmssfff}&dtCurr={dtCurr:yyyyMMddHHmmssfff}"; + string fullUrl = $"{urlOdlStartFromPOdl}{idxPODL}&doConfirm={doConfirm}&dtEve={dtEve:yyyyMMddHHmmssfff}&dtCurr={dtCurr:yyyyMMddHHmmssfff}"; try { // invio chiamata URL x avvio PODL su macchina @@ -7407,7 +7431,7 @@ namespace IOB_WIN_NEXT.Iob // prova ad avviare/chiudere PODL relativo (eventualmente duplicandolo) dtEve = $"{dtStartPOdl:yyyyMMddHHmmssfff}"; dtCurr = $"{DateTime.Now:yyyyMMddHHmmssfff}"; - callUrl($"{urlOLDStartFromPODL}{idxPOdl}&dtEve={dtEve}&dtCurr={dtCurr}", false); + callUrl($"{urlOdlStartFromPOdl}{idxPOdl}&dtEve={dtEve}&dtCurr={dtCurr}", false); // ora chiamo chiusura... dtEve = $"{dtEndPOdl:yyyyMMddHHmmssfff}"; @@ -7418,115 +7442,67 @@ namespace IOB_WIN_NEXT.Iob } return answ; } - /// - /// Processa articolo (da descrizione): - /// - recuperando i dati PODL attivi - /// - cerca PRIMO articolo corrispondente - /// - x inviare chiamate ad MP-IO di chiusura precedente / apertura nuovo + /// Processa avvio PODL (ed eventuale chiusura precedente) /// - /// Articolo (descrizione) - /// DataOra di riferimento evento start - protected bool ArticleTryStartPodl(string artDescript, DateTime dtRif) + /// Cod Articolo del PODL da avviare + /// num pz richiesti + protected int TryCreatePodl(string codArt, int numPz) + { + int answ = 0; + string resp = callUrl($"{urlCreatePOdl}CodArt={codArt}&numPz={numPz}", false); + int.TryParse(resp, out answ); + return answ; + } + /// + /// Recupera ODL attivo su impianto + /// + protected int CurrOdl() + { + int answ = 0; + string sCurrODL = utils.callUrl(urlGetCurrODL); + int.TryParse(sCurrODL, out answ); + return answ; + } + /// + /// Processa avvio PODL 8ed eventuale chiusura precedente) + /// + /// Idx del PODL da avviare + /// DataOra di riferimento evento start + protected bool SendStartPodl(int idxPOdl, DateTime dtRif) { - - // confronto con gli ODL da gestire - - // lancio inizio del primo ODL dell'articolo, chiudendo eventuale ODL vecchio - - - // getArtCurrPODL IOB/getArtCurrPODL - // getCurrPODL IOB/getCurrPODL/SIMUL_03 - // getPODL IOB/getPODL/SIMUL_03?idxPODL=123 - - - // closePODL IOB/closePODL/SIMUL_03?idxPOdl=123&dtEve=20230323151100000&dtCurr=20230323221100000 - // closeODL IOB/closeODL/SIMUL_03?idxOdl=123 - - - // forceStartPOdl IOB/forceStartPOdl/SIMUL_03?idxPODL=123&dtEve=20230323151100000&dtCurr=20230323221100000 - // urlOLDStartFromPODL - - - - bool answ = false; -#if false - // init var - int idxPOdl = 0; - string rawVal = ""; - // leggo righe file! - var recipeRows = File.ReadAllLines(recipeFile); - // per ogni file ricevuto controlla se viene dal MES (cerca PODL) - string tokenSearch = "PODL"; - // recupero riga PODL... - var rowPodl = recipeRows.Where(x => x.Contains(tokenSearch)).FirstOrDefault(); - if (rowPodl != null) - { - DateTime dtStartPOdl = DateTime.Today; - int duration = 0; - DateTime dtEndPOdl = DateTime.Today.AddMinutes(10); - string dtEve = ""; - string dtCurr = ""; - - // inizio ricerca PODL - rawVal = rowPodl.Trim().Replace(tokenSearch, "").Replace("", ""); - int.TryParse(rawVal, out idxPOdl); - if (idxPOdl > 0) - { - // leggo inizio commessa - tokenSearch = ""; - var rowStart = recipeRows.Where(x => x.Contains(tokenSearch)).FirstOrDefault(); - if (rowStart != null) - { - rawVal = rowStart.Trim().Replace(tokenSearch, "").Replace("", ""); - DateTime.TryParse(rawVal, out dtStartPOdl); - } - - // leggo durata commessa - tokenSearch = ""; - var rowDurSec = recipeRows.Where(x => x.Contains(tokenSearch)).FirstOrDefault(); - if (rowDurSec != null) - { - rawVal = rowDurSec.Trim().Replace(tokenSearch, "").Replace("", ""); - int.TryParse(rawVal, out duration); - dtEndPOdl = dtStartPOdl.AddSeconds(duration); - } - - // prova ad avviare/chiudere PODL relativo (eventualmente duplicandolo) - dtEve = $"{dtStartPOdl:yyyyMMddHHmmssfff}"; - dtCurr = $"{DateTime.Now:yyyyMMddHHmmssfff}"; - callUrl($"{urlOLDStartFromPODL}{idxPOdl}&dtEve={dtEve}&dtCurr={dtCurr}", false); - - // ora chiamo chiusura... - dtEve = $"{dtEndPOdl:yyyyMMddHHmmssfff}"; - dtCurr = $"{DateTime.Now:yyyyMMddHHmmssfff}"; - callUrl($"{urlPODLClose}{idxPOdl}&dtEve={dtEve}&dtCurr={dtCurr}", false); - } - answ = true; - } -#endif + DateTime dtCurr = DateTime.Now; + // chiamata avvio PODL (a posteriori) + string resp = callUrl($"{urlOdlStartFromPOdl}{idxPOdl}&dtEve={dtRif}&dtCurr={dtCurr}", false); + answ = resp == "OK"; return answ; } /// - /// Processa articolo (da descrizione): - /// - recuperando i dati ODL CORRENTE - /// - cerca articolo corrispondente - /// - se corrisponde CHIUDE + /// Processa chiusura ODL /// - /// Articolo (descrizione) + /// Idx dell'ODL da chiudere /// DataOra di riferimento evento stop - protected bool ArticleTryCloseOdl(string artDescript, DateTime dtRif) + protected bool SendCloseOdl(int idxOdl, DateTime dtRif) { bool answ = false; - - // getCurrODL IOB/getCurrODL/SIMUL_03 - - // check articolo... se corrisponde... - - // closeODL IOB/closeODL/SIMUL_03?idxOdl=123 - + DateTime dtCurr = DateTime.Now; + string resp = callUrl($"{urlODLClose}{idxOdl}&dtEve={dtRif}&dtCurr={dtCurr}", false); + answ = resp == "OK"; + return answ; + } + /// + /// Processa chiusura PODL + /// + /// Idx del PODL da chiudere + /// DataOra di riferimento evento stop + protected bool SendClosePOdl(int idxPOdl, DateTime dtRif) + { + bool answ = false; + DateTime dtCurr = DateTime.Now; + string resp = callUrl($"{urlPODLClose}{idxPOdl}&dtEve={dtRif}&dtCurr={dtCurr}", false); + answ = resp == "OK"; return answ; } diff --git a/IOB-WIN-NEXT/IobFile/IobFileSoitaab.cs b/IOB-WIN-NEXT/IobFile/IobFileSoitaab.cs index 7efcd427..f7587e3d 100644 --- a/IOB-WIN-NEXT/IobFile/IobFileSoitaab.cs +++ b/IOB-WIN-NEXT/IobFile/IobFileSoitaab.cs @@ -460,8 +460,51 @@ namespace IOB_WIN_NEXT.IobFile return fatto; } - private string lastArtDescr = ""; - private bool isRunningSim = false; + private string redKeyProdRunState + { + get => redisMan.redHash($"IOB:CurrData:{cIobConf.codIOB}:prodDecod:isRunningState"); + } + private string redKeyProdLastArt + { + get => redisMan.redHash($"IOB:CurrData:{cIobConf.codIOB}:prodDecod:lastArtDesc"); + } + private string redKeyLogfileAct + { + get => redisMan.redHash($"IOB:CurrData:{cIobConf.codIOB}:LogFile:Act"); + } + private string redKeyLogfileLast + { + get => redisMan.redHash($"IOB:CurrData:{cIobConf.codIOB}:LogFile:Last"); + } + /// + /// Variabile isRunning (NON realtime) + /// + private bool isRunningState + { + get + { + bool answ = false; + string cStatus = redisMan.getRSV(redKeyProdRunState); + bool.TryParse(cStatus, out answ); + return answ; + } + set + { + redisMan.setRSV(redKeyProdRunState, $"{value}"); + } + } + private string lastArtDescr + { + get + { + string answ = redisMan.getRSV(redKeyProdLastArt); + return answ; + } + set + { + redisMan.setRSV(redKeyProdLastArt, value); + } + } /// /// Esegue processing + invio dati tab SignLog @@ -474,10 +517,8 @@ namespace IOB_WIN_NEXT.IobFile // init oggetto x processing Dictionary sigLogFromFile = new Dictionary(); // recupero i dati dai logs files, attuale e nuovo... - string redKeyAct = redisMan.redHash($"IOB:CurrData:{cIobConf.codIOB}:LogFile:Act"); - string redKeyLast = redisMan.redHash($"IOB:CurrData:{cIobConf.codIOB}:LogFile:Last"); - string fileAct = redisMan.getRSV(redKeyAct); - string fileLast = redisMan.getRSV(redKeyLast); + string fileAct = redisMan.getRSV(redKeyLogfileAct); + string fileLast = redisMan.getRSV(redKeyLogfileLast); // confronto con i dati dell'ultimo LOG FILE processato int lenghtAct = fileAct != null ? fileAct.Length : 0; int lenghtLast = fileLast != null ? fileLast.Length : 0; @@ -554,83 +595,148 @@ namespace IOB_WIN_NEXT.IobFile } } - // recupero elenco PODL corrente... - List reqPOdlList =MachineNextPodl(); + + /* ---------------------------------------------------------- + * processo righe x costruire una lista di eventi produzione: + * - elenco di eventi contapezzi + * - lista xODL come articolo + quantità prodotta (_1, _2, ...) + * - eventuale ultimo xODL che resta aperto + * + * successivamente processing + invio info raccolte + * - recupero PODL aperti + * - apertura/chiusura PODL esistenti + * - creazione PODL mancanti + * - dichiarazione contapezzi + * + * ---------------------------------------------------------- */ string sVal = ""; string descrArt = ""; + List elencoProdBatch = new List(); + ProdBatchData lastProdBatch = new ProdBatchData(); + // ora processo TUTTO x il generico caso fluxLog...... foreach (var fLog2send in logNew) { - var artProcessed = false; // separo per ";" var currData = fLog2send.valString.Split(';'); if (currData.Length > 1) { // per prima cosa fluxLog a prescindere... sVal = $"[LOGFILE]{currData[0]}|{currData[1]}"; - // chiamo accodamento... + // ...e chiamo accodamento accodaFLog(sVal, qEncodeFLog(fLog2send.dtRif, currData[0], currData[1])); - // veritico se sia simulazione o taglio... - if (currData[0] == "START") + switch (currData[0]) { - isRunningSim = currData[1] == "0"; - } - // LIMITATAMENTE al caso PARTCODE --> gestione inizio/fine PODL - else if (currData[0] == "PARTCODE" && !isRunningSim) - { - // prendo articolo senza indice (_1, _2, _3, ...) - descrArt = descrArt.Contains("_") ? currData[1].Substring(0, currData[1].IndexOf("_")) : currData[1]; - // cerco nell'elenco PODL scaricato, sennò provo a rileggere... - var candPOdl = reqPOdlList.Where(x => x.CodArticolo.Contains(descrArt)).ToList(); - if (candPOdl == null || candPOdl.Count == 0) - { - reqPOdlList = MachineNextPodl(); - } - // cerco di nuovo podl x articolo... - candPOdl = reqPOdlList.Where(x => x.CodArticolo.Contains(descrArt)).ToList(); - if (candPOdl != null || candPOdl.Count > 0) - { - // confronto con codice articolo ultimo corrente - if (lastArtDescr != currData[1]) + case "END": + // se è un end --> è comunque NON + runnning + isRunningState = false; // chiudo batch precedente + in elenco (SE era valido...) + if (!string.IsNullOrEmpty(lastProdBatch.codArt)) { - // cerco PODL corretto + lastProdBatch.dtEnd = fLog2send.dtRif; + elencoProdBatch.Add(lastProdBatch); + } + // reset articolo.. + lastArtDescr = ""; + // nuovo batch VUOTO + lastProdBatch = new ProdBatchData(); + contapezziPLC = 0; + break; + case "START": + isRunningState = currData[1] == "1"; + break; - // chiamo avvio PODL e chiudo eventuali altri precedenti... - artProcessed = ArticleTryStartPodl(currData[1], fLog2send.dtRif); - if (artProcessed) + case "PARTCODE": + // inizio confronto articolo con precedente x capire se sia NUOVO + descrArt = currData[1]; + // devo scartare i "doppi percorsi" + if (descrArt != lastArtDescr) + { + // verifico se sia DAVVERO cambiato articolo... prendo articolo senza indice (_1, _2, _3, ...) + var artDataLast = lastArtDescr.Split('_'); + var artDataNew = descrArt.Split('_'); + // nuovo articolo (NON vuoto) + if (!string.IsNullOrEmpty(artDataNew[0]) && artDataLast[0] != artDataNew[0]) { - // salvo lastArt... - lastArtDescr = currData[1]; - - // tolgo PODL da lista... - - // FIXME TODO + // chiudo batch precedente + in elenco (SE era valido...) + if (!string.IsNullOrEmpty(lastProdBatch.codArt)) + { + // chiudo prod + lastProdBatch.dtEnd = fLog2send.dtRif; + elencoProdBatch.Add(lastProdBatch); + } + // nuovo batch + lastProdBatch = new ProdBatchData() + { + codArt = artDataNew[0], + dtStart = fLog2send.dtRif, + numPz = 1 + }; } + // solo nuova copia articolo + else + { + // aumento numPezzi batch + lastProdBatch.numPz++; + } + + // salvo nuovo art processato + lastArtDescr = descrArt; } - } - } - // se fosse un VERO end chiude ODL dell'ultimo articolo... - else if (currData[0] == "END") - { - // se è ancora presente un articolo... - if (!string.IsNullOrEmpty(lastArtDescr)) - { - // chiamo chiusura art corrente... - artProcessed = ArticleTryCloseOdl(lastArtDescr, fLog2send.dtRif); - if (artProcessed) - { - lastArtDescr = ""; - } - } + break; + + default: + break; } } } + // recupero elenco PODL corrente... + List reqPOdlList = MachineNextPodl(); + // adesso processo tutti i prodBatch collezionati x invio + foreach (var item in elencoProdBatch) + { + int currIdxPOdl = 0; + // cerco se articolo sia in elenco PODL + var listPOdl = reqPOdlList + .Where(x => x.CodArticolo.Equals(item.codArt, StringComparison.InvariantCultureIgnoreCase)) + .ToList(); + + // se trovato --> invio start/stop PODL + if (listPOdl != null && listPOdl.Count > 0) + { + var currPodl = listPOdl.FirstOrDefault(); + if (currPodl != null) + { + currIdxPOdl = currPodl.IdxPromessa; + // elimino da elenco PODL + reqPOdlList.Remove(currPodl); + } + } + else + { + // se NON trovato --> creo PODL, poi avvio/chiudo + currIdxPOdl = TryCreatePodl(item.codArt, item.numPz); + } + // se idxPOdl valido + if (currIdxPOdl > 0) + { + // mando apertura PODL + SendStartPodl(currIdxPOdl, item.dtStart); + // chiudo PODL! + SendClosePOdl(currIdxPOdl, item.dtStart); + // incremento contapezzi generale x ogni set di pezzi (se non realtime sarà a posteriori... pazienza...) + contapezziPLC += item.numPz; + + // provo ad inviare pezzi + trySendPzCountBlock(""); + } + } + // salvo in last il valore di act... - redisMan.setRSV(redKeyLast, fileAct); + redisMan.setRSV(redKeyLogfileLast, fileAct); // calcolo B_input valido var lastRec = sigLogData.LastOrDefault(); if (lastRec != null) @@ -644,7 +750,7 @@ namespace IOB_WIN_NEXT.IobFile } return fatto; } - + #endregion Private Methods }