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