diff --git a/IOB-UT-NEXT/CustomObj.cs b/IOB-UT-NEXT/CustomObj.cs index 206c00f3..9ed6adef 100644 --- a/IOB-UT-NEXT/CustomObj.cs +++ b/IOB-UT-NEXT/CustomObj.cs @@ -116,6 +116,7 @@ namespace IOB_UT_NEXT public string Note { get; set; } = ""; public string CodCli { get; set; } = ""; public DateTime InsertDate { get; set; } = DateTime.Now; + public string Recipe { get; set; } = ""; public string CodFase { diff --git a/IOB-UT-NEXT/baseUtils.cs b/IOB-UT-NEXT/baseUtils.cs index cf312fdd..866e16c9 100644 --- a/IOB-UT-NEXT/baseUtils.cs +++ b/IOB-UT-NEXT/baseUtils.cs @@ -720,10 +720,7 @@ namespace IOB_UT_NEXT { string dirPath = file.Substring(0, file.LastIndexOf('\\')); // verifico directory - if (!Directory.Exists(dirPath)) - { - Directory.CreateDirectory(dirPath); - } + checkDir(dirPath); string[] lines = dictionary.OrderBy(i => i.Key).Select(kvp => kvp.Key + ":" + kvp.Value).ToArray(); try { @@ -735,6 +732,21 @@ namespace IOB_UT_NEXT } } + /// + /// Test esistenza/creazione directory + /// + /// + public static void checkDir(string dirPath) + { + if (!Directory.Exists(dirPath)) + { + lg.Info($"Dir not found: {dirPath}"); + Directory.CreateDirectory(dirPath); + lg.Info($"reated local dir {dirPath}"); + } + } + + #endregion Public Methods #region Protected Properties diff --git a/IOB-UT-NEXT/fileMover.cs b/IOB-UT-NEXT/fileMover.cs index 4c02a6cc..c9b8f9f4 100644 --- a/IOB-UT-NEXT/fileMover.cs +++ b/IOB-UT-NEXT/fileMover.cs @@ -240,10 +240,7 @@ namespace IOB_UT_NEXT else if (theEntry.IsDirectory) { string strNewDirectory = @"" + baseDirectory + @"\" + theEntry.Name; - if (!Directory.Exists(strNewDirectory)) - { - Directory.CreateDirectory(strNewDirectory); - } + baseUtils.checkDir(strNewDirectory); } } ZipStream.Close(); @@ -309,13 +306,8 @@ namespace IOB_UT_NEXT } else if (theEntry.IsDirectory) { - string strNewDirectory = @"" + baseDirectory + @"\" + - - theEntry.Name; - if (!Directory.Exists(strNewDirectory)) - { - Directory.CreateDirectory(strNewDirectory); - } + string strNewDirectory = @"" + baseDirectory + @"\" + theEntry.Name; + baseUtils.checkDir(strNewDirectory); } } ZipStream.Close(); diff --git a/IOB-UT-NEXT/plcMemMapExt.cs b/IOB-UT-NEXT/plcMemMapExt.cs index 43b39c9c..c7247713 100644 --- a/IOB-UT-NEXT/plcMemMapExt.cs +++ b/IOB-UT-NEXT/plcMemMapExt.cs @@ -18,9 +18,9 @@ namespace IOB_UT_NEXT /// public Dictionary fileDecod { get; set; } = new Dictionary(); /// - /// Lista dei percorsi filepath attivi x gestioni IN/OUT varie + /// Lista ulteriori configurazioni KeyValuePair /// - public Dictionary actPath { get; set; } = new Dictionary(); + public Dictionary optKVP { get; set; } = new Dictionary(); } } diff --git a/IOB-WIN-NEXT/AdapterForm.cs b/IOB-WIN-NEXT/AdapterForm.cs index 772ec28a..0494d2eb 100644 --- a/IOB-WIN-NEXT/AdapterForm.cs +++ b/IOB-WIN-NEXT/AdapterForm.cs @@ -1602,7 +1602,7 @@ namespace IOB_WIN_NEXT string dirPath = $"{path}\\DATA\\{IOBConf.serverData.ClientInstall}"; string fullPath = $"{dirPath}\\{fileName}"; // verifica directory - Directory.CreateDirectory(dirPath); + baseUtils.checkDir(dirPath); // salvataggio File.WriteAllText(fullPath, confJson); diff --git a/IOB-WIN-NEXT/DATA/CONF/BAGLIETTO_CIMOLAI_01.ini b/IOB-WIN-NEXT/DATA/CONF/BAGLIETTO_CIMOLAI_01.ini index 49d4672c..1686a423 100644 --- a/IOB-WIN-NEXT/DATA/CONF/BAGLIETTO_CIMOLAI_01.ini +++ b/IOB-WIN-NEXT/DATA/CONF/BAGLIETTO_CIMOLAI_01.ini @@ -58,7 +58,7 @@ ENABLE_DYN_DATA=FALSE FORCE_DYN_DATA=TRUE ENABLE_DATA_FILTER=TRUE ENABLE_CLI_RESTART=TRUE -MAX_ELAPSED_TIME_SEC=120 +MAX_ELAPSED_TIME_SEC=60 MAX_TRY_PING=3 DISABLE_SEND_WDST=TRUE FTP_SERVER=192.168.60.234 diff --git a/IOB-WIN-NEXT/DATA/CONF/MAIN.ini b/IOB-WIN-NEXT/DATA/CONF/MAIN.ini index 81f793f1..fb1cc61e 100644 --- a/IOB-WIN-NEXT/DATA/CONF/MAIN.ini +++ b/IOB-WIN-NEXT/DATA/CONF/MAIN.ini @@ -45,13 +45,13 @@ CLI_INST=SteamWareSim ;STARTLIST=BAGLIETTO_CIMOLAI_01 ;STARTLIST=SIMUL_01 ;STARTLIST=GIACO_SAIM_003 -;STARTLIST=SIMUL_01 ;STARTLIST=PIZ09 ;STARTLIST=IMI_RIMOR_SAB_01 ;STARTLIST=IMI_RIMOR_SAB_02 ;STARTLIST=IMI_RIMOR_VER_01 ;STARTLIST=IMI_RIMOR_VER_02 ;STARTLIST=IMI_PAMA_392 -STARTLIST=IMI_PAMA_392 +;STARTLIST=Tend_FIMAT_01 +STARTLIST=SIMUL_02 MAXCNC=10 \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.ini b/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.ini index eb83abc3..8a671de6 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.ini +++ b/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.ini @@ -80,7 +80,6 @@ TC_MAX_INCR=5 MAX_PZ_INCR_PERC=1000 ; conf parametri memoria READ/WRITE PARAM_CONF=SIMUL_02.json - ;conf test FTP FTP_SERVER=ftp.steamware.net FTP_USER=testftpuser diff --git a/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.json b/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.json index 482f00ef..5399f8a6 100644 --- a/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.json +++ b/IOB-WIN-NEXT/DATA/CONF/SIMUL_02.json @@ -95,5 +95,20 @@ "NumPed": 11, "PackPed": 12, "PesoPack": 13 + }, + "optKVP": { + "hasRecipe": true, + "maxPodlQty": 530, + "useLocalRecipe": true, + "path-locBase": "C:\\MesData\\Local", + "path-remBase": "C:\\MesData\\Remote", + "path-00-Arch": "ArchivioRicette\\FIMAT", + "path-01-Temp": "01-Temp\\FIMAT", + "path-02-Sent": "02-Inviate\\FIMAT", + "path-03-Recv": "03-Ricevute\\FIMAT", + "path-04-remW": "C:\\MesData\\Remote\\Queue2", + "path-05-remR": "C:\\MesData\\Remote\\Dosed", + "replace-": "{{PODL}}", + "replace-": "Kg{{Qty}} | {{Note}}" } } \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/Tend_FIMAT_01.ini b/IOB-WIN-NEXT/DATA/CONF/Tend_FIMAT_01.ini index 93767b12..f7bb0592 100644 --- a/IOB-WIN-NEXT/DATA/CONF/Tend_FIMAT_01.ini +++ b/IOB-WIN-NEXT/DATA/CONF/Tend_FIMAT_01.ini @@ -63,21 +63,18 @@ ENABLE_DYN_DATA=TRUE FORCE_DYN_DATA=TRUE ; gestione delta minimo accettabile tra min/MAX DELTA_VAL=0.1 - ; clock base (da 10ms) timerIntMs=10 - ; conf parametri memoria READ/WRITE PARAM_CONF=Tend_FIMAT_01.json - NO_PING=FALSE ; conf blocchi memoria x READ MEM_BLOCK=Tend_FIMAT_01_MBlock.json ; conf aree allarme ALARM_CONF=Tend_FIMAT_01_alarm.json - ; rimozione check limiti min/max dynData disDynDataRangeCheck=true + [BRANCH] NAME=master \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/Tend_FIMAT_01.json b/IOB-WIN-NEXT/DATA/CONF/Tend_FIMAT_01.json index 45b78ff4..1acb1d55 100644 --- a/IOB-WIN-NEXT/DATA/CONF/Tend_FIMAT_01.json +++ b/IOB-WIN-NEXT/DATA/CONF/Tend_FIMAT_01.json @@ -301,15 +301,23 @@ "ManualBitCond": "40002.1=1", "EStopBitCond": "40002.0=1", "WorkIntCond": "40000|1=3", - "VarInt2Translate": "40001,40007", - "VarBit2Translate": "40003" + //"VarInt2Translate": "40001,40007", + //"VarBit2Translate": "40003" }, - "actPath": { - "recTempPath": "DATA/CONF/RECIPE/FIMAT", - "recSentPath": "DATA/SENT", - "recDestPath": "y:/", - "ordExecPath": "Z:/", - "ordArchPath": "DATA/RETURN" + "optKVP": { + "hasRecipe": true, + "maxPodlQty": 530, + "useLocalRecipe": true, + "path-locBase": "E:\\MesData\\", + "path-remBase": "C:\\MesData\\Remote", + "path-00-Arch": "ArchivioRicette\\FIMAT", + "path-01-Temp": "01-Temp\\FIMAT", + "path-02-Sent": "02-Inviate\\FIMAT", + "path-03-Recv": "03-Ricevute\\FIMAT", + "path-04-remW": "Y:\\", + "path-05-remR": "Z:\\", + "replace-": "{{PODL}}", + "replace-": "Kg{{Qty}} | {{Note}}" }, "itemTranslation": { "40001_0": "Stato non aggiornato per mancanza comunicazione da computer", diff --git a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj index 6063a0cf..18357e13 100644 --- a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj +++ b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj @@ -886,7 +886,9 @@ - + + PreserveNewest + @@ -912,7 +914,9 @@ - + + PreserveNewest + diff --git a/IOB-WIN-NEXT/IobGeneric.cs b/IOB-WIN-NEXT/IobGeneric.cs index a3be0e3a..f776272e 100644 --- a/IOB-WIN-NEXT/IobGeneric.cs +++ b/IOB-WIN-NEXT/IobGeneric.cs @@ -2133,6 +2133,8 @@ namespace IOB_WIN_NEXT processAutoOdl(); // verifico se devo gestire auto generazione dossier quotidiana processAutoDossier(); + // effettua gestione import file se configurato... + processFileImport(); } else if (ciclo == gatherCycle.VLF) { @@ -2280,6 +2282,22 @@ namespace IOB_WIN_NEXT return outVal; } + /// + /// Cerca se esiste il parametro opzionale nei KVP (JSON) e lo restituisce + /// + /// + /// + public string getOptJsonKVP(string key) + { + string answ = ""; + // controllo SE HO il parametro + if (memMap.optKVP.ContainsKey(key)) + { + answ = memMap.optKVP[key]; + } + return answ; + } + /// /// Cerca se esiste il parametro opzionale e lo restituisce /// @@ -4277,6 +4295,11 @@ namespace IOB_WIN_NEXT /// protected DateTime forcePzResetUntil = DateTime.Now.AddMinutes(-1); + /// + /// Determina se siano gestite le ricette + /// + protected bool hasRecipe = false; + /// /// Array dei contatori x segnali blinking /// @@ -4337,6 +4360,11 @@ namespace IOB_WIN_NEXT /// protected int maxErroriCheck = utils.CRI("maxErroriCheck"); + /// + /// Quantità massima per singola ricetta (per determinare num ricette da inviare) + /// + protected int maxQtyPerFile = 0; + /// /// Num massimo di errori di rete read (dal PLC) /// @@ -4382,6 +4410,11 @@ namespace IOB_WIN_NEXT /// protected Dictionary TSVC_Data = new Dictionary(); + /// + /// Indica se usare archivio locale ricette vs scarico http/REST + /// + protected bool useLocalRecipe = true; + /// /// Dizionario di VARIABILI da trattare come eventi (da inviare quando cambiano oppure a /// scadenza periodo...) @@ -4547,13 +4580,58 @@ namespace IOB_WIN_NEXT /// Elenco di valori da tradurre da valori BIT (es ModBus TCP FIMAT) /// NB: potrebbero essere contemporaneamente attivi + valori e + traduzioni /// - protected Dictionary OptVar2TranslBit { get; set; } = new Dictionary(); + protected Dictionary OptVar2TranslBit { get; set; } = new Dictionary(); /// /// Elenco di valori da tradurre da valori INT esclusivi (es ModBus TCP FIMAT) /// protected Dictionary OptVar2TranslInt { get; set; } = new Dictionary(); + /// + /// Elenco dei path utili x processing + /// + protected Dictionary pathList { get; set; } = new Dictionary(); + + /// + /// Gestione archivio serializzato PODL inviati (tramite file temp locale/REDIS) + /// + protected Dictionary POdlSentFileArch + { + get + { + Dictionary answ = new Dictionary(); + string redKey = redisMan.redHash($"IOB:Cache:{cIobConf.codIOB}:POdlSent"); + string rawData = redisMan.getRSV(redKey); + if (!string.IsNullOrEmpty(rawData)) + { + try + { + answ = JsonConvert.DeserializeObject>(rawData); + lgInfo($"Rilettura status POdlSentFileArch: trovati {answ.Count} record"); + } + catch (Exception exc) + { + lgError($"Errore in deserializzazione POdlSentFileArch{Environment.NewLine}{exc}"); + } + } + return answ; + } + set + { + string rawVal = JsonConvert.SerializeObject(value); + string redKey = redisMan.redHash($"IOB:Cache:{cIobConf.codIOB}:POdlSent"); + redisMan.setRSV(redKey, rawVal); + lgDebug($"Salvataggio status POdlSentFileArch | {value.Count} record"); + } + } + + /// + /// Elenco corrente (in memory) PODL inviati all'impianto + /// chiave: idxPODL + /// valore: record PODL + /// + protected Dictionary POdlSentList { get; set; } = new Dictionary(); + /// /// Indica se sia stato resettato un contapezzi /// @@ -4577,6 +4655,11 @@ namespace IOB_WIN_NEXT } } + /// + /// Definizioni x replace in file ricette + /// + protected Dictionary RecipeReplRules { get; set; } = new Dictionary(); + /// /// Indica se vada inviata la key richiesta con lo split/autoODL /// @@ -5103,15 +5186,9 @@ namespace IOB_WIN_NEXT // se ok --> sposto invio DateTime adesso = DateTime.Now; string archBasePath = Path.Combine(basePath, "DATA", "HIST", $"{adesso:yyyy}"); - if (!Directory.Exists(archBasePath)) - { - Directory.CreateDirectory(archBasePath); - } + baseUtils.checkDir(archBasePath); string archPath = Path.Combine(archBasePath, $"{adesso:MMddHHmmss}"); - if (!Directory.Exists(archPath)) - { - Directory.CreateDirectory(archPath); - } + baseUtils.checkDir(archPath); lgInfo($"Richiesta Dir Move | {localPath} | {archPath}"); foreach (var item in fileList) { @@ -5143,12 +5220,7 @@ namespace IOB_WIN_NEXT string basePath = Application.StartupPath; string tempDir = Path.Combine(basePath, locDir); lgInfo($"iobWriteLocalCSV | locDir: {locDir} | sAddHeader: {sAddHeader} | tempDir: {tempDir}"); - if (!Directory.Exists(tempDir)) - { - lgInfo("CSV: tempDir not found"); - Directory.CreateDirectory(tempDir); - lgInfo($"CSV: created local dir {tempDir}"); - } + baseUtils.checkDir(tempDir); string filePath = Path.Combine(tempDir, "articoli.csv"); answ = DataExport.SaveToCsv(ListaArticoli, filePath, addHeader); if (answ) @@ -5196,9 +5268,10 @@ namespace IOB_WIN_NEXT } return answ; } + /// - /// Effettua traduzione ITEM da LUT parametrica (key: lemma) del file di conf, se non - /// trovo uso key + /// Effettua traduzione ITEM da LUT parametrica (key: lemma) del file di conf, se non trovo + /// uso key /// /// /// @@ -5622,6 +5695,7 @@ namespace IOB_WIN_NEXT setupMemMap(); setupOptMemPar(); setupFileDecod(); + setupSpecialParams(); } catch (Exception exc) { @@ -5726,15 +5800,9 @@ namespace IOB_WIN_NEXT string errore = ""; // verifico archivio string dirArchive = Path.Combine(fileImportFolder, "archive"); - if (!Directory.Exists(dirArchive)) - { - Directory.CreateDirectory(dirArchive); - } + baseUtils.checkDir(dirArchive); string dirConvert = Path.Combine(fileImportFolder, "converted"); - if (!Directory.Exists(dirConvert)) - { - Directory.CreateDirectory(dirConvert); - } + baseUtils.checkDir(dirConvert); Dictionary statsColl = new Dictionary(); // cerco files da convertire var listFiles2Conv = Directory.GetFiles(fileImportFolder, fileImportType); @@ -5800,10 +5868,7 @@ namespace IOB_WIN_NEXT if (!answ) { string dirError = $"{fileImportFolder}/errors"; - if (!Directory.Exists(dirError)) - { - Directory.CreateDirectory(dirError); - } + baseUtils.checkDir(dirError); // sposto file... File.Move(fileItem, $"{dirError}/{Path.GetFileName(fileItem)}"); // segno errore! @@ -5892,6 +5957,158 @@ namespace IOB_WIN_NEXT } } + /// + /// Prepara la ricetta indicata partendo dai dati della ricetta template + dati ODL di riferimento + /// + /// Path del file template della ricetta + /// Record del PODL da inviare + /// Path della ricetta da inviare + protected virtual bool RecipePrepare(string tempPath, string recFilePath, PODLModel podlReq) + { + bool fatto = false; + // leggo il file template ricetta + var rawData = File.ReadAllText(recFilePath); + string fixContent = rawData; + // eseguo sostituzioni + foreach (var rule in RecipeReplRules) + { + string replVal = rule.Value; + // calcolo la sostituzione per i valori SPECIFICI... + if (replVal.Contains("{{PODL}}")) + { + replVal = replVal.Replace("{{PODL}}", $"PODL{podlReq.IdxPromessa:00000000}"); + } + if (replVal.Contains("{{Qty}}")) + { + replVal = replVal.Replace("{{Qty}}", $"{podlReq.NumPezzi}"); + } + if (replVal.Contains("{{Note}}")) + { + replVal = replVal.Replace("{{Note}}", $"{podlReq.Note}"); + } + fixContent = fixContent.Replace(rule.Key, replVal); + } + // scrivo file (secondo quantità...)! + string destPath = Path.Combine(tempPath, $"PODL{podlReq.IdxPromessa:00000000}.xml"); + if (podlReq.NumPezzi <= maxQtyPerFile) + { + File.WriteAllText(destPath, fixContent); + fatto = true; + } + else + { + int numReq = (int)Math.Ceiling((double)podlReq.NumPezzi / maxQtyPerFile); + // splitto e scrivo... + for (int i = 1; i <= numReq; i++) + { + destPath = Path.Combine(tempPath, $"PODL{podlReq.IdxPromessa:00000000}-{i}.xml"); + File.WriteAllText(destPath, fixContent); + } + fatto = true; + } + return fatto; + } + + /// + /// Prepara le ricette dato path temp scaricando elenco PODL + /// + /// + /// Percorso temp di appoggio x preparare ricette (compreso nome macchina) + /// + /// + /// Indica se usare le copie locali delle ricette oppure richiedere da remoto (REST get) + /// + /// + protected virtual bool RecipeReqWriteLocal(string tempPath, bool useLocal) + { + bool fatto = false; + + List reqPOdlList = new List(); + // per prima cosa recupero elenco PODL da gestire.... + var rawListPODL = callUrl(urlGetCurrPODL, false); + if (!string.IsNullOrEmpty(rawListPODL)) + { + try + { + reqPOdlList = JsonConvert.DeserializeObject>(rawListPODL); + } + catch (Exception exc) + { + lg.Error($"Errore: chiamata elenco PODL ha restituito errore{Environment.NewLine}{exc}"); + } + } + else + { + lg.Error($"Errore: chiamata elenco PODL ({urlGetCurrPODL}) ha restituito valore vuoto"); + } + // proseguo se ne ho trovati... + if (reqPOdlList.Count > 0) + { + // in questo elenco devo considerare solo PODL ATTIVI... + List actPOdlList = reqPOdlList.Where(x => x.Attivabile).ToList(); + // da questo elenco,se è rimasto qualcosa, ciclo x ricette da inviare + foreach (var actPodlReq in actPOdlList) + { + // devo escludere i PODL già gestiti + if (!POdlSentList.ContainsKey(actPodlReq.IdxPromessa)) + { + string recFilePath = ""; + try + { + // calcolo path ricetta... + recFilePath = Path.Combine(pathList["path-locBase"], pathList["path-00-Arch"], actPodlReq.Recipe); + // preparo file ricetta x PODL + bool fileOk = RecipePrepare(tempPath, recFilePath, actPodlReq); + if (fileOk) + { + // aggiungo PODL ad elenco dei processati + POdlSentList.Add(actPodlReq.IdxPromessa, actPodlReq); + // indico fatto (almeno per 1 è ok...) + fatto = true; + } + } + catch (Exception exc) + { + lgError($"recipeReqWriteLocal | Errore durante ciclo verifica ricetta | idxPODL {actPodlReq.IdxPromessa} | recFilePath {recFilePath}{Environment.NewLine}{exc}"); + } + } + } + // salvo su file elenco PODL gestiti/inviati + POdlSentFileArch = POdlSentList; + } + return fatto; + } + + /// + /// Effettua invio delle ricette alla macchina + /// + /// Area dove si trovano i fiel da trasmettere + /// Area archivio + /// Area remota dove inviare files + /// + protected bool RecipeSend(string localPath, string localArch, string remotePath) + { + bool fatto = false; + // recupero elenco files... + var fileList = Directory.GetFiles(localPath); + string srcName = ""; + string archName = ""; + string destName = ""; + if (fileList != null && fileList.Count() > 0) + { + foreach (var file in fileList) + { + srcName = Path.Combine(localPath, file); + archName = Path.Combine(localArch, file); + destName = Path.Combine(remotePath, file); + File.Copy(srcName, destName, true); + File.Move(srcName, archName); + } + fatto = true; + } + return fatto; + } + /// /// Cancella dal server i task eseguiti /// @@ -6225,6 +6442,39 @@ namespace IOB_WIN_NEXT } } + /// + /// Init parametri speciali, tipicamente KVP opzionali da json + /// + protected virtual void setupSpecialParams() + { + string sCond = ""; + // per prima cosa inizializzo lista PODL inviati + POdlSentList = POdlSentFileArch; + + // check modalità ricetta attiva + bool.TryParse(getOptJsonKVP("hasRecipe"), out hasRecipe); + + // verifico se usare ricette locali/http... + bool.TryParse(getOptJsonKVP("useLocalRecipe"), out useLocalRecipe); + + // recupero quantitativo massimo KG x PODL + int.TryParse(getOptJsonKVP("maxPodlQty"), out maxQtyPerFile); + + // recupero le folder specifiche x IN/OUT ricette filtrando direttamente l'area di memoria... + sCond = "path"; + var dirList = memMap.optKVP + .Where(x => x.Key.StartsWith(sCond)) + .ToList(); + pathList = dirList.ToDictionary(x => x.Key, x => x.Value); + + // gestione replace in file ricette... + sCond = "replace-"; + var ruleList = memMap.optKVP + .Where(x => x.Key.StartsWith(sCond)) + .ToList(); + RecipeReplRules = ruleList.ToDictionary(x => x.Key.Replace(sCond, ""), x => x.Value); + } + /// /// Cleanup stringa x impiego tipo ident da char dubbi /// @@ -6675,7 +6925,7 @@ namespace IOB_WIN_NEXT if (!OptVar2TranslBit.ContainsKey(memKey)) { // init traduzione vuota - OptVar2TranslBit.Add(memKey,""); + OptVar2TranslBit.Add(memKey, ""); } } } @@ -6693,7 +6943,7 @@ namespace IOB_WIN_NEXT if (!OptVar2TranslInt.ContainsKey(memKey)) { // init traduzione vuota - OptVar2TranslInt.Add(memKey,""); + OptVar2TranslInt.Add(memKey, ""); } } } diff --git a/IOB-WIN-NEXT/IobModbusTCPFimat.cs b/IOB-WIN-NEXT/IobModbusTCPFimat.cs index 7978d9ec..0e4333a6 100644 --- a/IOB-WIN-NEXT/IobModbusTCPFimat.cs +++ b/IOB-WIN-NEXT/IobModbusTCPFimat.cs @@ -1,6 +1,8 @@ -using System; +using IOB_UT_NEXT; +using System; using System.Collections.Generic; -using System.Xml.Serialization; +using System.IO; +using System.Linq; using static IOB_UT_NEXT.CustomObj; namespace IOB_WIN_NEXT @@ -28,6 +30,7 @@ namespace IOB_WIN_NEXT { lgInfo("NEW IOB ModBus TCP FIMAT"); + setupSpecialParams(); // provo lettura una prima volta i dati DYN if (currPLC != null && currPLC.Connected) { @@ -36,7 +39,6 @@ namespace IOB_WIN_NEXT processDynData(); if (EnableTest) { - processDataSync(); testReadExt(); } } @@ -45,312 +47,22 @@ namespace IOB_WIN_NEXT lgError($"Eccezione in processDynData iniziale x ModBus TCP FIMAT:{Environment.NewLine}{exc}"); } } - } - - /// - /// Elenco dei path validi x processing, tra cui - /// - archivio template ricette - /// - archivio PODL ricette inviate - /// - path remota invio PODL - /// - path remota lettura tasl ([P]ODL) svolti - /// - archivio task ([P]ODL) recuperati - /// - protected List pathlist { get; set; } = new List(); - - /// - /// Prepara la ricetta indicata partendo dai dati della ricetta template + dati ODL di riferimento - /// - /// Path del template della ricetta - /// Record del PODL da inviare - /// Path della ricetta da inviare - protected string prepareRecipe(string recTemplatePath, PODLModel podlReq) - { - string recFilePath = ""; - // leggo il file template ricetta - - - return recFilePath; - } - /// - /// Effettua invio XML del PODL dato il suo path verso la macchina - /// - /// - /// - protected bool sendRecipe(string odlRecipePath) - { - bool fatto = false; - - return fatto; - } - - /// - /// Verifica l'elenco dei PODL (Attivi) per la macchina e verifica se vadano inviati (controllando archivio PODL inviati - /// - /// - /// - protected bool trySendPOdl(List actPOdlList) - { - bool answ = false; - foreach (var item in actPOdlList) + if (EnableTest) { - // verifico se sia nella folder di quelli inviati - - // se non presente preparo, leggendo conf del NUMERO ricetta (e configurandola come 10'000+num???) - - // infine invio + processDataSync(); } - return answ; } - #endregion Public Constructors - #region Public Classes + #region Protected Fields - [XmlRoot(ElementName = "A_Recipe")] - public class ARecipe - { - #region Public Properties + /// + /// Quantità massima PODL prima di fare split ordine (default 999'999) + /// + protected int maxPodlQty = 999999; - [XmlElement(ElementName = "ColRecipe")] - public List ColRecipe { get; set; } - - [XmlElement(ElementName = "DesRecipe")] - public DesRecipe DesRecipe { get; set; } - - [XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")] - public string Xsi { get; set; } - [XmlAttribute(AttributeName = "noNamespaceSchemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")] - public string NoNamespaceSchemaLocation { get; set; } - - #endregion Public Properties - } - - [XmlRoot(ElementName = "ColData")] - public class ColData - { - #region Public Properties - - [XmlElement(ElementName = "ColourCode")] - public string ColourCode { get; set; } - - [XmlElement(ElementName = "CompNumber")] - public int CompNumber { get; set; } - - [XmlElement(ElementName = "Cost")] - public double Cost { get; set; } - - [XmlElement(ElementName = "Date")] - public DateTime Date { get; set; } - - [XmlElement(ElementName = "Description")] - public string Description { get; set; } - - [XmlElement(ElementName = "DosDuration")] - public int DosDuration { get; set; } - - [XmlElement(ElementName = "DosError")] - public string DosError { get; set; } - - [XmlElement(ElementName = "DosNote")] - public object DosNote { get; set; } - - [XmlElement(ElementName = "Origin")] - public string Origin { get; set; } - - [XmlElement(ElementName = "PartsPerc")] - public double PartsPerc { get; set; } - - [XmlElement(ElementName = "PartsWeight")] - public double PartsWeight { get; set; } - - [XmlElement(ElementName = "TypComp")] - public string TypComp { get; set; } - - [XmlElement(ElementName = "Weight-gr")] - public double Weightgr { get; set; } - - [XmlElement(ElementName = "Weight-gr-dosed")] - public double Weightgrdosed { get; set; } - - [XmlElement(ElementName = "Weight-gr-prev")] - public double Weightgrprev { get; set; } - - [XmlElement(ElementName = "Weight-gr-total")] - public double Weightgrtotal { get; set; } - - #endregion Public Properties - } - - [XmlRoot(ElementName = "ColRecipe")] - public class ColRecipe - { - #region Public Properties - - [XmlElement(ElementName = "ColData")] - public ColData ColData { get; set; } - - #endregion Public Properties - } - - [XmlRoot(ElementName = "DesData")] - public class DesData - { - #region Public Properties - - [XmlElement(ElementName = "Article")] - public string Article { get; set; } - - [XmlElement(ElementName = "CustDrumCode")] - public object CustDrumCode { get; set; } - - [XmlElement(ElementName = "Customer")] - public object Customer { get; set; } - - [XmlElement(ElementName = "Date")] - public DateTime Date { get; set; } - - [XmlElement(ElementName = "Design")] - public int Design { get; set; } - - [XmlElement(ElementName = "DosDuration")] - public int DosDuration { get; set; } - - [XmlElement(ElementName = "DosedLine")] - public int DosedLine { get; set; } - - [XmlElement(ElementName = "DosType")] - public string DosType { get; set; } - - [XmlElement(ElementName = "DrumCode")] - public double DrumCode { get; set; } - - [XmlElement(ElementName = "DrumInitialWeightKG")] - public double DrumInitialWeightKG { get; set; } - - [XmlElement(ElementName = "DrumTag")] - public int DrumTag { get; set; } - - [XmlElement(ElementName = "DrumType")] - public int DrumType { get; set; } - - [XmlElement(ElementName = "Info1")] - public object Info1 { get; set; } - - [XmlElement(ElementName = "Info2")] - public object Info2 { get; set; } - - [XmlElement(ElementName = "Info3")] - public object Info3 { get; set; } - - [XmlElement(ElementName = "Info4")] - public object Info4 { get; set; } - - [XmlElement(ElementName = "Info5")] - public object Info5 { get; set; } - - [XmlElement(ElementName = "Info6")] - public object Info6 { get; set; } - - [XmlElement(ElementName = "Info7")] - public object Info7 { get; set; } - - [XmlElement(ElementName = "Info8")] - public object Info8 { get; set; } - - [XmlElement(ElementName = "Info9")] - public object Info9 { get; set; } - - [XmlElement(ElementName = "LotID")] - public object LotID { get; set; } - - [XmlElement(ElementName = "Note1")] - public string Note1 { get; set; } - - [XmlElement(ElementName = "Note2")] - public object Note2 { get; set; } - - [XmlElement(ElementName = "OrderCode")] - public string OrderCode { get; set; } - - [XmlElement(ElementName = "Prio")] - public string Prio { get; set; } - - [XmlElement(ElementName = "Quantity-kg")] - public double Quantitykg { get; set; } - - [XmlElement(ElementName = "Quantity-kg-dosed")] - public double Quantitykgdosed { get; set; } - - [XmlElement(ElementName = "RecipeStatus")] - public string RecipeStatus { get; set; } - - [XmlElement(ElementName = "RecipeType")] - public string RecipeType { get; set; } - - [XmlElement(ElementName = "RecName")] - public int RecName { get; set; } - - [XmlElement(ElementName = "ReqType")] - public string ReqType { get; set; } - - [XmlElement(ElementName = "Screen")] - public object Screen { get; set; } - - [XmlElement(ElementName = "Sequence")] - public int Sequence { get; set; } - - [XmlElement(ElementName = "SequenceTot")] - public int SequenceTot { get; set; } - - [XmlElement(ElementName = "Series")] - public int Series { get; set; } - - [XmlElement(ElementName = "ServiceType")] - public string ServiceType { get; set; } - - [XmlElement(ElementName = "SplitCurrent")] - public int SplitCurrent { get; set; } - - [XmlElement(ElementName = "SplitTotal")] - public int SplitTotal { get; set; } - - [XmlElement(ElementName = "Taglio-D")] - public double TaglioD { get; set; } - - [XmlElement(ElementName = "Taglio-N")] - public double TaglioN { get; set; } - - [XmlElement(ElementName = "UM")] - public int UM { get; set; } - - [XmlElement(ElementName = "Variant")] - public object Variant { get; set; } - - [XmlElement(ElementName = "ViscoName")] - public object ViscoName { get; set; } - - [XmlElement(ElementName = "ViscoValue")] - public double ViscoValue { get; set; } - - #endregion Public Properties - } - - // using System.Xml.Serialization; XmlSerializer serializer = new - // XmlSerializer(typeof(ARecipe)); using (StringReader reader = new StringReader(xml)) { var - // test = (ARecipe)serializer.Deserialize(reader); } - [XmlRoot(ElementName = "DesRecipe")] - public class DesRecipe - { - #region Public Properties - - [XmlElement(ElementName = "DesData")] - public DesData DesData { get; set; } - - #endregion Public Properties - } - - #endregion Public Classes + #endregion Protected Fields #region Protected Properties @@ -466,17 +178,59 @@ namespace IOB_WIN_NEXT B_input = byteSignals; } + /// - /// Effettua sync dati + /// Effettua sync dati x PODL attivi /// protected override void processDataSync() { - // richiesta check autoODL - processAutoOdl(); - // richiesta generazione quotidiana dossiers - processAutoDossier(); - // effettua gestione import file... - processFileImport(); + DateTime adesso = DateTime.Now; + string tempPath = Path.Combine(pathList["path-locBase"], pathList["path-01-Temp"]); + string archPath = Path.Combine(pathList["path-locBase"], pathList["path-02-Sent"], $"{adesso:yyyy}", $"{adesso:MM}"); + string remoPath = Path.Combine(pathList["path-locBase"], pathList["path-04-remW"]); + baseUtils.checkDir(tempPath); + baseUtils.checkDir(archPath); + // recupero elenco PODL da processare, check PODL già inviati, save locale + bool create = RecipeReqWriteLocal(tempPath, useLocalRecipe); + // invio ricette a impianto + bool trasmitted = RecipeSend(tempPath, archPath, remoPath); + } + + /// + /// Cerca di recuperare i file generati dall'impianto in merito al processing degli ordini + /// + /// + protected override bool processFileImport() + { + bool fatto = false; + // cerca e sposta i NUOVI file + + // per ogni file ricevuto controlla se sia corrispondente ad un file inviato (cerca PODL) + + // se trova PODL prova ad avviare/chiudere PODL relativo (eventualmente duplicandolo) + + return fatto; + } + + + /// + /// Verifica l'elenco dei PODL (Attivi) per la macchina e verifica se vadano inviati + /// (controllando archivio PODL inviati) + /// + /// + /// + protected bool trySendPOdl(List actPOdlList) + { + bool answ = false; + foreach (var item in actPOdlList) + { + // verifico se sia nella folder di quelli inviati + + // se non presente preparo, leggendo conf del NUMERO ricetta (e configurandola come 10'000+num???) + + // infine invio + } + return answ; } #endregion Protected Methods diff --git a/IOB-WIN-NEXT/IobSimula.cs b/IOB-WIN-NEXT/IobSimula.cs index 7831c95d..08965efd 100644 --- a/IOB-WIN-NEXT/IobSimula.cs +++ b/IOB-WIN-NEXT/IobSimula.cs @@ -3,6 +3,7 @@ using MapoSDK; using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using static IOB_UT_NEXT.CustomObj; @@ -79,6 +80,7 @@ namespace IOB_WIN_NEXT simDich = setupSimPar("SIM_DICH"); int.TryParse(getOptPar("SIM_MATR_OPR"), out matrOpr); } + // riesegue setup PLC setParamPlc(); // ricarico da server i dati dei pezzi fatti... lgInfo("Init contapezzi SIMULA: pzCntReload(true)"); @@ -93,17 +95,31 @@ namespace IOB_WIN_NEXT // parto processando dynData processDynData(); - // test gestione fileImport... - if (!string.IsNullOrEmpty(fileImportFolder)) - { - processFileImport(); - } if (!string.IsNullOrEmpty(getOptPar("FTP_AT_START"))) { // simulazione processo FTP (Cimolai) - FIXME TODO DeleteME processDataSync(); } + // test ricetta + if (hasRecipe) + { + string tempPath = Path.Combine(pathList["path-locBase"], pathList["path-01-Temp"]); + string archPath = Path.Combine(pathList["path-locBase"], pathList["path-02-Sent"], $"{adesso:yyyy}", $"{adesso:MM}"); + string remoPath = Path.Combine(pathList["path-locBase"], pathList["path-04-remW"]); + baseUtils.checkDir(tempPath); + baseUtils.checkDir(archPath); + // recupero elenco PODL da processare, check PODL già inviati, save locale + bool create = RecipeReqWriteLocal(tempPath, useLocalRecipe); + // invio ricette a impianto + bool trasmitted = RecipeSend(tempPath, archPath, remoPath); + } + + // test gestione fileImport... + if (!string.IsNullOrEmpty(fileImportFolder)) + { + processFileImport(); + } } #endregion Public Constructors