Sviluppo ForceStartPOdl

This commit is contained in:
Samuele Locatelli
2022-11-10 11:10:38 +01:00
parent d0af9aa18f
commit 0a8a0f0eb2
2 changed files with 389 additions and 19 deletions
+31 -11
View File
@@ -320,13 +320,33 @@ namespace MP_IO.Controllers
/// <returns>Esito chiamata (OK/vuoto)</returns>
public string forceSplitOdl(string id)
{
// attenzione! poiché nell'URL il carattere "#" fiene filtrato ci aspettiamo il
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
id = id.Replace("|", "#");
DataLayer DataLayerObj = new DataLayer();
return DataLayerObj.AutoStartOdl(id, true, true, 100, "");
}
/// <summary>
/// Avvia PODL indicato
/// - se esistesse un ODL da altro PODL --> chiude
/// - se fosse già in essere ODL collegato --> lascia aperto
/// - se fosse chiuso ODL collegato --> duplica PODL e poi avvia nuovo ODL.
///
/// GET: IOB/forceStartPOdl/SIMUL_03?idxPODL=123
/// </summary>
/// <param name="id"></param>
/// <param name="idxPODL">idx del PDL da avviare</param>
/// <returns>Esito chiamata (OK/vuoto)</returns>
public string forceStartPOdl(string id,int idxPODL)
{
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
id = id.Replace("|", "#");
DataLayer DataLayerObj = new DataLayer();
return DataLayerObj.ForceStartPOdl(id, idxPODL, true);
}
/// <summary> Chiude ODL precedente ed avvia uno nuovo (duplicandolo e sitemando quantità
/// RIMANENTE), e CONFERMA produzione...
///
@@ -338,7 +358,7 @@ namespace MP_IO.Controllers
/// <returns>Esito chiamata (OK/vuoto)</returns>
public string forceSplitOdlFull(string id, bool doConfirm, bool qtyFromLast, int? roundStep, string keyRichiesta = "")
{
// attenzione! poiché nell'URL il carattere "#" fiene filtrato ci aspettiamo il
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
id = id.Replace("|", "#");
DataLayer DataLayerObj = new DataLayer();
@@ -452,7 +472,7 @@ namespace MP_IO.Controllers
/// <returns>Json contenente la riga di stato macchina</returns>
public string getCurrData(string id)
{
// attenzione! poiché nell'URL il carattere "#" fiene filtrato ci aspettiamo il
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
id = id.Replace("|", "#");
string answ = "";
@@ -531,7 +551,7 @@ namespace MP_IO.Controllers
/// <returns></returns>
public string getCurrOdlRow(string id)
{
// attenzione! poiché nell'URL il carattere "#" fiene filtrato ci aspettiamo il
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
id = id.Replace("|", "#");
string answ = "";
@@ -558,7 +578,7 @@ namespace MP_IO.Controllers
/// <returns></returns>
public string getCurrOdlStart(string id)
{
// attenzione! poiché nell'URL il carattere "#" fiene filtrato ci aspettiamo il
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
id = id.Replace("|", "#");
DateTime answ = new DateTime(DateTime.Now.Year - 1, 12, 31);
@@ -589,7 +609,7 @@ namespace MP_IO.Controllers
/// <returns>Json contenente lista oggetti PODL serializzati</returns>
public string getCurrPODL(string id)
{
// attenzione! poiché nell'URL il carattere "#" fiene filtrato ci aspettiamo il
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
if (!string.IsNullOrEmpty(id))
{
@@ -618,7 +638,7 @@ namespace MP_IO.Controllers
/// <returns></returns>
public string getCurrStatoRow(string id)
{
// attenzione! poiché nell'URL il carattere "#" fiene filtrato ci aspettiamo il
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
id = id.Replace("|", "#");
string answ = "";
@@ -686,7 +706,7 @@ namespace MP_IO.Controllers
/// <returns></returns>
public int getIdlePeriod(string id)
{
// attenzione! poiché nell'URL il carattere "#" fiene filtrato ci aspettiamo il
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
id = id.Replace("|", "#");
int answ = 0;
@@ -774,7 +794,7 @@ namespace MP_IO.Controllers
public string getLastDossArt(string id)
{
string answ = "";
// attenzione! poiché nell'URL il carattere "#" fiene filtrato ci aspettiamo il
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
if (string.IsNullOrEmpty(id))
{
@@ -809,7 +829,7 @@ namespace MP_IO.Controllers
public string getLastDossByMacc(string id)
{
string answ = "";
// attenzione! poiché nell'URL il carattere "#" fiene filtrato ci aspettiamo il
// attenzione! poiché nell'URL il carattere "#" viene filtrato ci aspettiamo il
// carattere "|" che poi trasformiamo ora in "#"
if (string.IsNullOrEmpty(id))
{
@@ -1283,7 +1303,7 @@ namespace MP_IO.Controllers
}
else
{
logger.lg.scriviLog($"remTask2Exe: impossibile riconoscere il comando {taskName} come uno deitipi ammessi, NON aggiunto", tipoLog.ERROR);
logger.lg.scriviLog($"remTask2Exe: impossibile riconoscere il comando {taskName} come uno dei tipi ammessi, NON rimosso", tipoLog.ERROR);
}
answ = getTask2Exe(id);
}
+358 -8
View File
@@ -1,12 +1,12 @@
using MapoSDK;
using Newtonsoft.Json;
using PdfSharp.Charting;
using SteamWare;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading;
@@ -297,7 +297,16 @@ namespace MapoDb
/// <returns></returns>
public static string currOdlRowHash(string idxMacchina)
{
return mHash(string.Format("CurrOdlRow:{0}", idxMacchina));
return mHash($"CurrOdlRow:{idxMacchina}");
}
/// <summary>
/// Hash dati PODL ROW x la macchina specificata
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public static string getPOdlRowHash(int idxPODL)
{
return mHash($"PODLRow:{idxPODL}");
}
/// <summary>
@@ -485,6 +494,15 @@ namespace MapoDb
{
return mHash($"VetoOdlMacc:{idxMacchina}");
}
/// <summary>
/// Hash x VETO force Start PODL la macchina specificata
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public static string vetoForceStartPOdlMaccHash(string idxMacchina)
{
return mHash($"VetoStartPOdlMacc:{idxMacchina}");
}
/// <summary>
/// verifica se sia da reinviare un task alla macchina dall'elenco di quelli salvati (in
@@ -1209,17 +1227,18 @@ namespace MapoDb
{
DS_ProdTempi.ODLDataTable answTab = null;
string rCall = "";
string rKey = currOdlRowHash(idxMacchina);
if (memLayer.ML.CRB("IOB_RedEnab"))
{
saveCallRec("hasODL_row");
try
{
rCall = memLayer.ML.getRSV(currOdlRowHash(idxMacchina));
rCall = memLayer.ML.getRSV(rKey);
if (!string.IsNullOrEmpty(rCall))
{
answTab = JsonConvert.DeserializeObject<DS_ProdTempi.ODLDataTable>(rCall);
}
else
if (answTab == null || answTab.Count == 0)
{
// istanzio un NUOVO oggetto lettura
MapoDb connDb = new MapoDb();
@@ -1227,7 +1246,7 @@ namespace MapoDb
// salvo in redis...
rCall = JsonConvert.SerializeObject(answTab);
int currOdlRowCacheDur = memLayer.ML.CRI("currOdlRowCacheDur");
memLayer.ML.setRSV(currOdlRowHash(idxMacchina), rCall, currOdlRowCacheDur);
memLayer.ML.setRSV(rKey, rCall, currOdlRowCacheDur);
}
}
catch (Exception exc)
@@ -1244,6 +1263,48 @@ namespace MapoDb
return answTab;
}
/// <summary>
/// Restituisce il valore dell'intera RIGA PODL data chiave (da redis o da DB se non trovata...)
/// </summary>
/// <param name="idxPODL">IDX della PODL</param>
/// <returns></returns>
public DS_ProdTempi.PromesseODLDataTable getPODLRowTab(int idxPODL)
{
DS_ProdTempi.PromesseODLDataTable answTab = null;
string rCall = "";
string rKey = getPOdlRowHash(idxPODL);
if (memLayer.ML.CRB("IOB_RedEnab"))
{
saveCallRec("hasPODL_row");
try
{
rCall = memLayer.ML.getRSV(rKey);
if (!string.IsNullOrEmpty(rCall))
{
answTab = JsonConvert.DeserializeObject<DS_ProdTempi.PromesseODLDataTable>(rCall);
}
if (answTab == null || answTab.Count == 0)
{
answTab = taPODL.getByKey(idxPODL);
// salvo in redis...
rCall = JsonConvert.SerializeObject(answTab);
int currOdlRowCacheDur = memLayer.ML.CRI("currOdlRowCacheDur");
memLayer.ML.setRSV(rKey, rCall, currOdlRowCacheDur);
}
}
catch (Exception exc)
{
logger.lg.scriviLog($"Eccezione in recupero getPODLRowTab{Environment.NewLine}{exc}", tipoLog.EXCEPTION);
}
}
else
{
answTab = taPODL.getByKey(idxPODL);
}
return answTab;
}
/// <summary>
/// Restituisce il valore dell'intera RIGA stato macchina corrente (da redis o da DB se non trovata...)
/// </summary>
@@ -1388,6 +1449,295 @@ namespace MapoDb
return fatto;
}
/// <summary> Effettua force Start PODL
/// [CurrProdStatus = 1] se fosse già in essere ODL collegato --> lascia aperto
/// [CurrProdStatus = 2] se esistesse un ODL da altro PODL x diverso articolo/fase --> chiude vecchio x poi far partire nuovo
/// [CurrProdStatus = 3] se fosse chiuso ODL collegato --> duplica PODL e poi avvia nuovo ODL
/// [CurrProdStatus = 4] se fosse già in essere ODL non collegato --> lascia aperto e collego
/// </summary>
/// <param name="idxMacchina">macchina</param> <param name="idxPODL">IDX PODL da
/// processare</param> <param name="doConfirm">effettuare conferma qty</param> STEP x cui
/// arrotondare la quantità prox ODL (corrente come riferimento) </param> <returns></returns>
public string ForceStartPOdl(string idxMacchina, int idxPODL, bool doConfirm)
{
string answ = "KO";
int CurrProdStatus = 0;
string sIdxODL = "";
string redKey = vetoForceStartPOdlMaccHash(idxMacchina);
// verifico NON CI SIA un veto a NUOVI split... 30 sec di default...
string rawData = memLayer.ML.getRSV(redKey);
if (string.IsNullOrEmpty(rawData))
{
// registro VETO x altri split... 30sec
memLayer.ML.setRSV(redKey, $"Inizio FORCE START PODL: {idxPODL} | {DateTime.Now}", 30);
// calcolo la qta da gestire
int qtyConf = 0;
if (doConfirm)
{
DS_ProdTempi.stp_PzProd_getByMacchinaRow rigaProd;
try
{
rigaProd = taPzProd2conf.GetData(idxMacchina)[0];
qtyConf = rigaProd.pezziNonConfermati;
}
catch (Exception exc)
{
logger.lg.scriviLog($"Errore recupero pezzi da confermare per la macchina {idxMacchina}{Environment.NewLine}{exc}", tipoLog.ERROR);
}
}
// proseguo
DS_ProdTempi.ODLDataTable currODLData = null;
DS_ProdTempi.PromesseODLDataTable reqPODLData = null;
DS_ProdTempi.ODLRow OdlRow = null;
DS_ProdTempi.PromesseODLRow POdlRow = null;
// metodo principale...
try
{
sIdxODL = getCurrODL(idxMacchina);
// recupero dati da PODL
reqPODLData = getPODLRowTab(idxPODL);
// recupero ODL corrente...
currODLData = currODLRowTab(idxMacchina);
// procedo SOLO SE ho trovato un PODL
if (reqPODLData != null && reqPODLData.Rows.Count > 0)
{
POdlRow = reqPODLData[0];
// prima cosa: verifico se sia un PODL libero (idxODL==0)
if (reqPODLData[0].IdxODL == 0)
{
if (currODLData != null && currODLData.Count > 0)
{
OdlRow = currODLData[0];
// verifico ODL corrente, se compatibili...
if (OdlRow.CodArticolo == POdlRow.CodArticolo && OdlRow.KeyRichiesta == POdlRow.KeyRichiesta && OdlRow.IdxMacchina == POdlRow.IdxMacchina)
{
// compatibili --> caso 4
CurrProdStatus = 4;
}
else
{
// anche qui chiusura ed avvio
CurrProdStatus = 2;
}
}
else
{
CurrProdStatus = 2;
}
}
// altrimenti se PODL già associato
else
{
// se trovo qualcosa come ODL
if (currODLData != null && currODLData.Count > 0)
{
OdlRow = currODLData[0];
// se è quello già associato
if ($"{reqPODLData[0].IdxODL}" == sIdxODL)
{
// non devo fare nulla
CurrProdStatus = 1;
}
else
{
// altrimenti devo clonare
CurrProdStatus = 3;
}
}
else
{
// anche in questo caso devo clonare PODL
CurrProdStatus = 3;
}
}
}
else
{
logger.lg.scriviLog($"Errore in ForceStartPOdl: non trovato PODL per idxPODL{idxPODL}", tipoLog.ERROR);
}
// OVVIAMENTE solo se ho POdlRow...
if (POdlRow != null)
{
switch (CurrProdStatus)
{
case 1:
// --> non tocco nulla PODL/ODL
logger.lg.scriviLog($"Richiesto ForceStartPOdl, caso 1 | PODL {idxPODL} | ODL {sIdxODL} | nessun intervento", tipoLog.INFO);
break;
case 2:
// eventuale chiusura vecchio ODL
if (currODLData.Count > 0)
{
doCloseCurrODL(idxMacchina, doConfirm, qtyConf, currODLData, DateTime.Now);
}
// avvio PODL: creo nuovo ODL da promessa ed associo
taODL.inizioSetupPromessa(idxPODL, MatrOpr, POdlRow.IdxMacchina, POdlRow.TCAssegnato, POdlRow.PzPallet, POdlRow.Note);
// fix (invio ) dati ODL
Thread.Sleep(1000);
answ = saveOdlData(idxMacchina, currODLData, reqPODLData);
break;
case 3:
// eventuale chiusura vecchio ODL
if (currODLData.Count > 0)
{
doCloseCurrODL(idxMacchina, doConfirm, qtyConf, currODLData, DateTime.Now);
}
// duplico PODL... inserisco nuovo record...
taPODL.insertQuery(POdlRow.KeyRichiesta, POdlRow.KeyBCode, true, POdlRow.CodArticolo, POdlRow.CodGruppo, POdlRow.IdxMacchina, POdlRow.NumPezzi, POdlRow.TCAssegnato, POdlRow.DueDate, POdlRow.Priorita, POdlRow.PzPallet, POdlRow.Note);
// recupero odl attivabili...
var podlList = taPODL.getByCodArt(POdlRow.CodArticolo, true);
// cerco quello che ha la stessa fase/macchina e + recente...
var lastPodl = podlList.Where(x => x.KeyRichiesta == POdlRow.KeyRichiesta && x.IdxMacchina == POdlRow.IdxMacchina).OrderByDescending(x => x.idxPromessa).FirstOrDefault();
int newPODL = lastPodl != null ? lastPodl.idxPromessa : POdlRow.idxPromessa;
// avvio (nuovo) PODL
taODL.inizioSetupPromessa(idxPODL, MatrOpr, POdlRow.IdxMacchina, POdlRow.TCAssegnato, POdlRow.PzPallet, POdlRow.Note);
// fix (invio ) dati ODL
Thread.Sleep(1000);
answ = saveOdlData(idxMacchina, currODLData, reqPODLData);
break;
case 4:
// --> registro in PODL e non tocco ODL
break;
default:
break;
}
}
else
{ }
}
catch (Exception exc)
{
logger.lg.scriviLog($"Eccezione in ForceStartPOdl{Environment.NewLine}{exc}", tipoLog.EXCEPTION);
}
}
else
{
logger.lg.scriviLog($"VETO ATTIVO | Richiesto ForceStartPOdl per impianto {idxMacchina} | impossibile procedere");
}
return answ;
}
private string saveOdlData(string idxMacchina, DS_ProdTempi.ODLDataTable currODLData, DS_ProdTempi.PromesseODLDataTable reqPODLData)
{
string answ;
// recupera ODL macchina
var newOdl = currODL(idxMacchina, true);
// attendo 1000 msec
// registro fine ODL (idxTipoEv = 1)
int idxEvento = 1;
logger.lg.scriviLog($"Invio evento ODL-forced start per macchina {idxMacchina}, evento {idxEvento}, articolo {currODLData[0].CodArticolo}", tipoLog.INFO);
var resCmd = scriviRigaEventoBarcode(idxMacchina, idxEvento, currODLData[0].CodArticolo, "ODL-FORFCE-START");
// invio eventi setup a macchina....
string setArtVal = $"{currODLData[0].CodArticolo}";
string setPzCommVal = $"{reqPODLData[0].NumPezzi}";
string setCommVal = $"ODL{newOdl}";
if (!string.IsNullOrEmpty(reqPODLData[0].KeyRichiesta))
{
setCommVal = $"{reqPODLData[0].KeyRichiesta} ODL{newOdl}";
}
try
{
// invio task caricamento dati ODL
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);
}
catch
{ }
// chiamo refresh MSE
taMSE.forceRecalc(0, idxMacchina);
// resetto stato macchina...
memLayer.ML.redDelKey(currStatoMaccHash(idxMacchina));
answ = "OK";
logger.lg.scriviLog($"Effettuato reset e ricalcoli x split ODL per macchina {idxMacchina}", tipoLog.INFO);
// se è una master richiamo fix x child...
if (isMaster(idxMacchina))
{
string ts = "";
string outData = "";
taODL.fixMachineSlave(idxMacchina, 30, 1);
// ciclo su ogni slave la gestione reinvio pezzi -->calcolo gli slave...
var slaveList = taM2S.getByMaster(idxMacchina);
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}";
addTask4Machine(machine.IdxMacchinaSlave, taskType.fixStopSetup, 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);
}
}
return answ;
}
private bool doCloseCurrODL(string idxMacchina, bool doConfirm, int qtyConf, DS_ProdTempi.ODLDataTable currODLData, DateTime adesso)
{
bool fatto = false;
// registro un evento di inizio attrezzaggio (idxTipoEv = 2)
int idxEvento = 2;
logger.lg.scriviLog($"Invio evento CHIUSURA ODL per macchina {idxMacchina}, evento {idxEvento}, articolo {currODLData[0].CodArticolo}, qty confermata {qtyConf}", tipoLog.INFO);
// chiudo ALTRO ODL
inputComandoMapo resCmd = scriviRigaEventoBarcode(idxMacchina, idxEvento, currODLData[0].CodArticolo, "ODL-CLOSE", 0, "", adesso, adesso);
if (doConfirm)
{
// attendo 100 msec
Thread.Sleep(100);
adesso = DateTime.Now;
// chiamo conferma produzione...
try
{
string chiamata = confRett ? "confermaProdMacchinaFull" : "confermaProdMacchina";
logger.lg.scriviLog($"Chiamata a {chiamata} con parametri {currODLData[0].IdxMacchina} |{MatrOpr} | {DateTime.Now.AddDays(-10)} | {DateTime.Now} | {qtyConf} | 0 | 1 | {DateTime.Now} | false", tipoLog.INFO);
string idxMacchinaSel = currODLData[0].IdxMacchina;
if (confRett)
{
// confermo al netto dei pezzi lasciati...
fatto = confermaProdMacchinaFull(idxMacchinaSel, memLayer.ML.CRI("modoConfProd"), qtyConf, 0, 0, adesso);
}
else
{
fatto = confermaProdMacchina(idxMacchinaSel, memLayer.ML.CRI("modoConfProd"), qtyConf, 0, adesso);
}
if (!fatto)
{
logger.lg.scriviLog($"ERRORE in chiamata {chiamata}", tipoLog.ERROR);
}
}
catch (Exception exc)
{
logger.lg.scriviLog($"Eccezione in ConfermaProduzione{Environment.NewLine}{exc}", tipoLog.EXCEPTION);
}
}
// attendo 100 msec
Thread.Sleep(100);
// chiamo chiusura
MapoDbObj.taODL.forceClose(currODLData[0].IdxODL, idxMacchina);
// elimino eventuale ODL precedente...
string rKey = memLayer.ML.redHash($"ODL:{idxMacchina}");
memLayer.ML.setRSV(rKey, "");
fatto = true;
return fatto;
}
/// <summary>
/// GET elenco parametri correnti x IOB
/// </summary>
@@ -1894,7 +2244,7 @@ namespace MapoDb
DateTime dataOraEvento = DateTime.Now;
DateTime dtEvento, dtCorrente;
// controllo: se ho valori dt x evento e orario DIVERSI per acquisitore IOB calcolo
// dataOraEvento corretto
// dataOraEvento corretto
if (dtEve != dtCurr)
{
Int64 delta = 0;
@@ -1993,7 +2343,7 @@ namespace MapoDb
DateTime dataOraEvento = DateTime.Now;
DateTime dtEvento, dtCorrente;
// controllo: se ho valori dt x evento e orario DIVERSI per acquisitore IOB calcolo
// dataOraEvento corretto
// dataOraEvento corretto
if (dtEve != dtCurr)
{
// delta è un calcolo MOLTO approssimativo della differenza temporale...
@@ -2328,7 +2678,7 @@ namespace MapoDb
DateTime dataOraEvento = DateTime.Now;
DateTime dtEvento, dtCorrente;
// controllo: se ho valori dt x evento e orario DIVERSI per acquisitore IOB calcolo
// dataOraEvento corretto
// dataOraEvento corretto
if (dtEve != dtCurr)
{
Int64 delta = 0;