using MongoDB.Driver; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using NKC_SDK; using SteamWare; using System; using System.Collections.Generic; using System.IO; using System.Web; namespace AppData { /// /// Classe con metodi di supporto per COMUNICAZIONE /// public class ComLib { #region Gestione persistenza risposte via REST da NESTING /// /// Database corrente MongoDB /// IMongoDatabase database; /// /// Init classe ComLib /// public ComLib() { database = memLayer.ML.getMongoDatabase("NKC"); } /// /// Classe impiego sstatico ComLib... /// public static ComLib man = new ComLib(); /// /// Salva una risposta ricevuta x STIMA /// /// Stringa della risposta JSON ricevuta dal nesting /// public bool saveEstAnsw(nestReplyBatchInitial nestAnsw) { bool answ = false; try { // definisco filtro var filtBuilder = Builders.Filter; var filter = filtBuilder.Eq("BatchID", nestAnsw.BatchID); var collRawData = database.GetCollection("EstimationArchive"); // elimino old collRawData.DeleteMany(filter); // aggiungo collRawData.InsertOne(nestAnsw); answ = true; } catch { } return answ; } /// /// Salva una risposta ricevuta x NESTING /// /// Stringa della risposta JSON ricevuta dal nesting /// public bool saveNestAnsw(nestReplyBatchFinal nestAnsw) { bool answ = false; try { // definisco filtro var filtBuilder = Builders.Filter; var filter = filtBuilder.Eq("BatchID", nestAnsw.BatchID); var collRawData = database.GetCollection("NestingArchive"); // elimino old collRawData.DeleteMany(filter); // aggiungo collRawData.InsertOne(nestAnsw); answ = true; } catch { } return answ; } /// /// Recupero risposta stima salvata /// /// /// public nestReplyBatchInitial getEstAnsw(int BatchID) { nestReplyBatchInitial answ = null; try { // definisco filtro var filtBuilder = Builders.Filter; var filter = filtBuilder.Eq("BatchID", BatchID); var collRawData = database.GetCollection("EstimationArchive"); // recupero answ = collRawData.Find(filter).Project("{_id: 0}").FirstOrDefault(); } catch { } return answ; } /// /// Recupero risposta nesting salvata /// /// /// public nestReplyBatchFinal getNestAnsw(int BatchID) { nestReplyBatchFinal answ = null; try { // definisco filtro var filtBuilder = Builders.Filter; var filter = filtBuilder.Eq("BatchID", BatchID); FindOptions opz = new FindOptions { ShowRecordId = false }; var collRawData = database.GetCollection("NestingArchive"); // recupero answ = collRawData.Find(filter).Project("{_id: 0}").FirstOrDefault(); } catch { } return answ; } //public object getEstAnsw(int BatchId) //{ // List answ = null; // var collNAA = database.GetCollection("NestAnswArchive"); // // oggetto filtraggio x nest answ // var builderNAA = Builders.Filter; // var filtBatchId = builderNAA.Eq(u => u.BatchID, BatchId); // var datiCorrenti = collNAA.Find(filtBatchId); // foreach (var item in datiCorrenti) // { // } // return answ; //} /// /// restitusice ultima chiamata REST registrata su REDIS /// /// public static string lastRestAnsw() { string answ = ""; // recupero ultima call string redKey = $"{redNestAnsw}:LAST_CALL"; answ = memLayer.ML.getRSV(redKey); return answ; } #endregion /// /// Wrapper traduzione termini /// /// /// public static string traduci(string lemma) { return user_std.UtSn.Traduci(lemma); } #region conf posizioni redis public static string redOutPath = "NKC:SERV:BREQ"; public static string redMsgCount = "NKC:SERV:BREQ:MCount"; public static string redMsgList = "NKC:SERV:BREQ:MList"; public static string redMLCurrStack = "NKC:SERV:TAKT:CurrStack"; public static string redNestAnsw = "NKC:NEST:BANSW"; public static string redProdReq = "NKC:SERV:BUNKS"; public static string redProdAnsw = "NKC:PROD:BUNKS"; #endregion #region definizione classi impiegate con PROD public static string PositionStatusDescr(object value) { string answ = ""; try { BatchPosition pStatus = (BatchPosition)Enum.Parse(typeof(BatchPosition), value.ToString()); switch (pStatus) { case BatchPosition.NotStarted: answ = traduci("NotStarted"); break; case BatchPosition.StackStarted: answ = traduci("Stacking"); break; case BatchPosition.StackDone: answ = traduci("StackDone"); break; default: break; } } catch { } return answ; } public static string BatchStatusDescr(object value) { string answ = ""; try { BatchStatus bStatus = (BatchStatus)Enum.Parse(typeof(BatchStatus), value.ToString()); switch (bStatus) { case BatchStatus.Imported: answ = "Imported"; break; case BatchStatus.EstimationRequested: answ = "Estimation Requested"; break; case BatchStatus.EstimationDone: answ = "Estimation Completed"; break; case BatchStatus.NestRequested: answ = "Nesting Requested"; break; case BatchStatus.NestDone: answ = "Nesting Completed"; break; case BatchStatus.Approved: answ = "Nesting Approved"; break; case BatchStatus.Discarded: answ = "Nesting Discarded"; break; case BatchStatus.Errors: answ = "Nesting Impossibile (data errors)"; break; case BatchStatus.PartEval: answ = "Part/Item under evaluation"; break; case BatchStatus.PartOk: answ = "Part/Item Validated"; break; case BatchStatus.PartKo: answ = "Part/Item NOT Validated"; break; default: answ = $"Status unknown: {bStatus}"; break; } } catch { } return answ; } /// /// Oggetto globale TAKT /// public class Takt { /// /// Codice univoco oggetto TAKT (data.num) /// public string TaktId { get; set; } /// /// Stato del TAKT /// public CStatus Status { get; set; } /// /// Elenco degli Stack da lavorare /// public List StackList { get; set; } /// /// Numero di Stack da lavorare /// public int NumStack { get { int answ = 0; try { answ = StackList.Count; } catch { } return answ; } } } #endregion #region definizione classi impiegate con NEST public class Parte { public int PartId { get; set; } public string DataMatrix { get; set; } public string ExtCode { get; set; } public string Description { get; set; } public int MatId { get; set; } public string PostProc { get; set; } public string ProcessReq { get; set; } public string CadFilePath { get; set; } public int Qty { get; set; } } public class BatchData { /// /// ID del batch in esecuzione /// public int BatchId { get; set; } /// /// tempo amssimo eprmesso x nesting (minuti) /// public int maxTime { get; set; } /// /// Tipo di processing richiesto /// 1 = stima /// 2 = nesting /// [JsonConverter(typeof(StringEnumConverter))] public int procType { get; set; } /// /// Codice della amcchina x cui si effettua richeista /// [JsonConverter(typeof(StringEnumConverter))] public mType machineType { get; set; } /// /// Tipo di ordine richeisto /// [JsonConverter(typeof(StringEnumConverter))] public oType orderType { get; set; } } /// /// Salva su redis l'oggetto dei materiali serializzato /// /// public static bool sendMaterials() { bool answ = false; // leggo tab MNATERIALS da DB var table = DataLayer.man.taMat.GetData(); // serializzo string redVal = JsonConvert.SerializeObject(table); // salvo string redKey = $"NKC:SERV:CONF:MATERIALS"; // scrivo per ora solo su REDIS memLayer.ML.setRSV(redKey, redVal); return answ; } /// /// Restituisce il prossimo codice di envelope per comunicare con sistemi esterni /// /// Batch contenuto nell'envelope /// note opzionali (motivo envelope) /// public static string getNextEnv(int BatchID, string note) { // incremento counter long nextIndex = memLayer.ML.setRCntI(redMsgCount); // salvo contenuto della busta string answ = $"Z{nextIndex:000000000000}"; Dictionary lista = new Dictionary(); lista.Add(answ, $"{BatchID}|{note}"); memLayer.ML.redSaveHashDict(redMsgList, lista); // ritorno return answ; } /// /// Restituisce elenco KVP delle buste ancora "pending" (quando processate le elimina da elenco...) /// /// public static KeyValuePair[] getEnvList() { KeyValuePair[] answ = memLayer.ML.redGetHash(redMsgList); return answ; } /// /// resetta la richeista corrente in modo che non ce ne siano altre in coda /// /// public static bool resetBatchReq() { bool answ = false; try { currBatchReq = ""; answ = true; } catch { } return answ; } public static string currBatchReqKey { get { return $"{redOutPath}:CURR"; } } /// /// Valore della richiesta corrente di elaborazione batch /// public static string currBatchReq { get { return memLayer.ML.getRSV(currBatchReqKey); } set { // scrivo su REDIS memLayer.ML.setRSV(currBatchReqKey, value); } } public static bool sendFirstValidationBatch() { bool answ = false; // verifico se sia vuota la richeista corrente (= chiuso...) // ora verifico, se ci sono batch in stato 8 (da validare) --> metto in coda! var tabBatch = DataLayer.man.taBL.getByStatus(8, "", 1); bool hasValReq = tabBatch.Count > 0; if (hasValReq) { // invia a redis una richiesta... sendMaterials(); // recupero PRIMO batchID da validare int nextBatchId = 0; try { nextBatchId = tabBatch[0].BatchID; } catch { } if (nextBatchId > 0) { // richiedo! sendBatchReq(nextBatchId, "Estimation", 1); // registro su DB nesting iniziato... QUANDO MI RISPONDE dovrò verificare che era un abtch x VALIDAZIONE DataLayer.man.taBL.updateStatus(nextBatchId, (int)BatchStatus.EstimationRequested, "", 0); answ = true; } } // resituisco return answ; } /// /// Invia una richiesta di esecuzione di Nesting x un Batch /// /// Batch di cui si chiede processing /// note opzionali /// Tipo processo: 1 = stima, 2 = nesting /// public static bool sendBatchReq(int BatchID, string note, int pType) { bool answ = false; // per prima cosa mi serve una "nuova busta" per inviare i messaggi string nextEnv = getNextEnv(BatchID, note); // preparo il contenuto della busta ed invio i messaggi... try { // in base allo stato del BATCH corrente determino il tempo e le opzioni da inviare... var batch = DataLayer.man.taBL.getByKey(BatchID); int mTime = 1; if (batch[0].STATUS < (int)BatchStatus.EstimationDone) { mTime = memLayer.ML.cdvi("estimMaxTime"); } else { mTime = memLayer.ML.cdvi("nestMaxTime"); } // init oggetti x fare cicli... Order currOrder = null; Kit currentKit = null; Part currPart = null; List listOrder = new List(); List listKit = new List(); List listPart = new List(); // leggo tab ORDINI da DB var tblOrd = DataLayer.man.taOL.getByBatch(BatchID); // leggo tab KIT da DB var tblKit = DataLayer.man.taKL.getByBatch(BatchID); // leggo tab ITEMS da DB var tblItm = DataLayer.man.taIL.getByBatch(BatchID); // ciclo per comporre oggetto con cicli annidiati ext --> int foreach (var rigaOrd in tblOrd) { listKit = new List(); // compongo kit var righeKit = (DS_App.KitListRow[])tblKit.Select($"OrdID = {rigaOrd.OrdID}"); foreach (var rigaKit in righeKit) { listPart = new List(); // elenco ITEMS var righeItems = (DS_App.ItemListRow[])tblItm.Select($"KitID = {rigaKit.KitID}"); foreach (var rigaItem in righeItems) { currPart = new Part() { PartId = rigaItem.ItemID, PartExtCode = rigaItem.ItemExtCode, PartDtmx = rigaItem.ItemDtmx, PartQty = rigaItem.ItemQty, MatId = rigaItem.MatID, CadFilePath = rigaItem.CadFilePath }; listPart.Add(currPart); } // compongo KIT currentKit = new Kit() { KitId = rigaKit.KitID, KitExtCode = rigaKit.KitExtCode, PartList = listPart }; listKit.Add(currentKit); } // compongo ordine currOrder = new Order() { OrderId = rigaOrd.OrdID, OrderCod = rigaOrd.OrdCodOrig, OrderExtCode = rigaOrd.OrderExtCode, DestPlant = rigaOrd.DestPlant, KitList = listKit }; listOrder.Add(currOrder); } // oggetto complessivo batchRequest newBatchreq = new batchRequest() { BatchId = BatchID, EnvNum = nextEnv, MaxTime = mTime, ProcType = pType, MachineType = mType.Multiax, OrderType = oType.BatchRequest, OrderList = listOrder }; // serializzo string redVal = JsonConvert.SerializeObject(newBatchreq); // salvo string redKey = $"{redOutPath}:{nextEnv}"; // scrivo su REDIS memLayer.ML.setRSV(redKey, redVal); // invio notifica che c'è una busta da processare memLayer.ML.setRSV(currBatchReqKey, nextEnv); answ = true; } catch (Exception exc) { } // restituisco ok return answ; } /// /// Verifica lo stato di una richiesta di esecuzione BATCH x stima/nesting /// /// OfflineOrder di cui si chiede processing /// note opzionali /// public static bool checkBatchReq(int OffOrderID) { bool answ = false; #if false string typeSearch = "OffOrdCalculation"; string keyEnv = ""; // recupero lista dei vari task APERTI... KeyValuePair[] comAperte = getEnvList(); // processo x cercare ordine... foreach (var item in comAperte) { // cerco dove sia quello richiesto if (item.Value.Contains(typeSearch)) { // controllo SE sia quello richiesto if (item.Value == $"{OffOrderID}|{typeSearch}") { keyEnv = item.Key; break; } } } // controllo e se c'è risposta --> update DB string redKey = $"{redNestAnsw}:FULL:{keyEnv}"; string rawAnsw = memLayer.ML.getRSV(redKey); if (rawAnsw != "") { // cerco risposta come stack --> disegno... var offOrder = deserializeOfflineOrder(rawAnsw); // se ho in risposta 1 stack... if (offOrder.Stacks.Count == 1) { // se ho 1 solo sheet var sheets = offOrder.Stacks[0].SheetList; if (sheets.Count == 1) { // controllo se ho CNC prog answ = sheets[0].MachiningProgram != ""; if (answ) { // aggiorno su DB il disegno... string disegno = sheets[0].Drawing; DataLayer.man.taOffOL.updateDrawing(OffOrderID, disegno); } } } } #endif // restituisco ok return answ; } /// /// Invia una richiesta di esecuzione di CAM x un ordine offline /// /// OfflineOrder di cui si chiede processing /// note opzionali /// public static bool sendOfflineOrderReq(int OffOrderID, string note) { bool answ = false; // per prima cosa mi serve una "nuova busta" per inviare i messaggi string nextEnv = getNextEnv(OffOrderID, note); // preparo il contenuto della busta ed invio i messaggi... try { int mTime = 5; int pType = 1; // serializzo ordini come ARRAY VUOTO string redVal = "[]"; // salvo string redKey = $"{redOutPath}:{nextEnv}:ORDERS"; // scrivo su REDIS memLayer.ML.setRSV(redKey, redVal); // ora ITEMS var tblItm = DataLayer.man.taIL.getByOfflineOrder(OffOrderID); // serializzo redVal = JsonConvert.SerializeObject(tblItm); // salvo redKey = $"{redOutPath}:{nextEnv}:ITEMS"; // scrivo su REDIS memLayer.ML.setRSV(redKey, redVal); // ora versione gerarchica var currBatch = new BatchData() { BatchId = OffOrderID, maxTime = mTime, procType = pType, machineType = mType.Offline, orderType = oType.OfflineOrder }; // serializzo redVal = JsonConvert.SerializeObject(currBatch); // salvo redKey = $"{redOutPath}:{nextEnv}:DATA"; // scrivo su REDIS memLayer.ML.setRSV(redKey, redVal); // invio notifica che c'è una busta da processare memLayer.ML.setRSV(currBatchReqKey, nextEnv); answ = true; } catch (Exception exc) { logger.lg.scriviLog($"Eccezione in sendOfflineOrderReq:{Environment.NewLine}{exc}"); } // restituisco ok return answ; } /// /// Verifica lo stato di una richiesta di esecuzione /// /// OfflineOrder di cui si chiede processing /// note opzionali /// public static bool checkOfflineOrderReq(int OffOrderID) { bool answ = false; string typeSearch = "OffOrdCalculation"; string keyEnv = ""; // recupero lista dei vari task APERTI... KeyValuePair[] comAperte = getEnvList(); // processo x cercare ordine... foreach (var item in comAperte) { // cerco dove sia quello richiesto if (item.Value.Contains(typeSearch)) { // controllo SE sia quello richiesto if (item.Value == $"{OffOrderID}|{typeSearch}") { keyEnv = item.Key; break; } } } // controllo e se c'è risposta --> update DB string redKey = $"{redNestAnsw}:FULL:{keyEnv}"; string rawAnsw = memLayer.ML.getRSV(redKey); if (rawAnsw != "") { // cerco risposta come stack --> disegno... var offOrder = deserializeOfflineOrder(rawAnsw); // se ho in risposta 1+ sheets... if (offOrder.SheetList.Count > 0) { // se ho 1 solo sheet var sheets = offOrder.SheetList; // controllo se ho CNC prog answ = sheets[0].MachiningProgram != ""; if (answ) { // aggiorno su DB il disegno... string disegno = sheets[0].Drawing; DataLayer.man.taOffOL.updateDrawing(OffOrderID, disegno); } } } // restituisco ok return answ; } /// /// Salvo dati su PartList ricevuti da Nesting (COMPETATO) /// /// /// public static void updateBunksFromNesting(int BatchID, List BunkList) { // inizio a processare... bunks! if (BunkList != null) { foreach (var bunk in BunkList) { // creo il BUNK! var newBunk = DataLayer.man.taSTL.insertAndReturn(bunk.BunkIndex, BatchID); // se ho un bunk in risposta... if (newBunk.Count == 1) { var currBunk = newBunk[0]; // processo sheets if (bunk.SheetList != null) { foreach (var sheet in bunk.SheetList) { // creo lo sheet... var newSheet = DataLayer.man.taSHL.insertAndReturn(sheet.SheetIndex, sheet.MatId, (decimal)sheet.EstimatedWorktime, currBunk.StackID, sheet.PrintProgram, sheet.MachiningProgram, sheet.Drawing); // se ho 1 sheet in risposta if (newSheet.Count == 1) { var currSheet = newSheet[0]; // processo items! if (sheet.PartList != null) { foreach (var part in sheet.PartList) { // aggiungo part a sheet (in tab nesting) DataLayer.man.taNest.insertAndReturn(currSheet.SheetID, part.PartId); } } } } } } } } } /// /// Salvo dati su PartList ricevuti da Nesting (COMPETATO) /// /// /// public static void updateBinsFromNesting(int BatchID, List BinList) { // inizio a processare... bunks! if (BinList != null) { foreach (var item in BinList) { // creo il BIN! var newBin = DataLayer.man.taBN.insertAndReturn(item.BinIndex); // se ho un BIN in risposta... if (newBin.Count == 1) { var currBin = newBin[0]; // processo sheets if (item.PartList != null) { foreach (var part in item.PartList) { // creo lo sheet... var newB2I = DataLayer.man.taBNLS.insertAndReturn(currBin.BinID, part.PartId); } } } } } } /// /// Salvo dati su PartList ricevuti da Nesting (COMPETATO) /// /// /// public static void updateCartsFromNesting(int BatchID, List CartList) { // inizio a processare... bunks! if (CartList != null) { foreach (var item in CartList) { // creo il CART! var newCart = DataLayer.man.taCR.insertAndReturn(item.CartIndex); // se ho un CART in risposta... if (newCart.Count == 1) { var currCart = newCart[0]; // processo sheets if (item.KitList != null) { foreach (var kit in item.KitList) { // creo lo sheet... var updKit = DataLayer.man.taKL.updateCart(kit.KitId, currCart.CartID); } } } } } } /// /// Salvo dati su PartList ricevuti da Nesting (stima) /// /// public static void updatePartsFromNesting(List PartList) { string PostProcList = ""; string ProcessesReq = ""; string pdfFilePath = ""; // salvo elenco materiali x ogni item... foreach (Part currItem in PartList) { // calcolo parametri... PostProcList = getPostProcList(currItem.OptParameters); ProcessesReq = getProcessesReq(currItem.OptParameters); pdfFilePath = getPdfFilePath(currItem.OptParameters); DataLayer.man.taIL.updateFromNesting(currItem.PartId, currItem.MatId, PostProcList, ProcessesReq, pdfFilePath); } } /// /// Recupera le operazioni di PostProcessing, esempio: /// - T-Nut /// - Round /// - Chop /// /// /// public static string getPostProcList(Dictionary optParameters) { string answ = ""; foreach (var currOpt in optParameters) { switch (currOpt.Key) { case "ChopAtTab": case "RoundEdge": case "TNutFlag": // se contiene YES aggiungo... if (currOpt.Value.ToLower() == "yes") { answ += $"{currOpt.Key}#"; } break; } } // se finisce per "#" trimmo... if (answ.EndsWith("#")) { answ = answ.Substring(0, answ.Length - 1); } return answ; } /// /// Recupera le operazioni RICHIESTE a valle /// - Paint /// - Assembly /// - SecOp /// /// /// public static string getProcessesReq(Dictionary optParameters) { string answ = ""; foreach (var currOpt in optParameters) { switch (currOpt.Key) { case "AssemblyCell": case "PaintFlag": // se contiene YES aggiungo... if (currOpt.Value.ToLower() == "yes") { answ += $"{currOpt.Key}#"; } break; } } // se finisce per "#" trimmo... if (answ.EndsWith("#")) { answ = answ.Substring(0, answ.Length - 1); } return answ; } /// /// Recupera file pdf /// /// /// public static string getPdfFilePath(Dictionary optParameters) { string answ = ""; if (optParameters.ContainsKey("PdfLink")) { answ = optParameters["PdfLink"]; } return answ; } #endregion #region metodi helper di conversione /// /// Helper x serializzare l'oggetto /// /// /// public static string serializeTakt(Takt currData) { string answ = JsonConvert.SerializeObject(currData); return answ; } /// /// Helper x deserializzare l'oggetto /// /// /// public static Takt deserializeTakt(string rawData) { Takt answ = JsonConvert.DeserializeObject(rawData); return answ; } /// /// Deserializza un ordine offline /// /// /// public static nestReplyOffOrd deserializeOfflineOrder(string rawData) { nestReplyOffOrd answ = null; try { answ = JsonConvert.DeserializeObject(rawData); } catch { } return answ; } #endregion #region metodi x data persistence /// /// Salvo il Takt inviato /// /// Origine del dato: SERV / PROD / NEST /// /// public static bool saveTakt(string origin, Takt currData) { bool answ = false; try { // calcolo valori redis string redKey = $"NKC:{origin.ToUpper()}:TAKT:{currData.TaktId}"; string redVal = serializeTakt(currData); // scrivo per ora solo su REDIS memLayer.ML.setRSV(redKey, redVal); answ = true; } catch { } return answ; } /// /// Leggo il Takt inviato /// /// Origine del dato: SERV / PROD / NEST /// /// public static Takt readTakt(string origin, string TaktId) { Takt answ = null; try { string redKey = $"NKC:{origin.ToUpper()}:TAKT:{TaktId}"; string redVal = memLayer.ML.getRSV(redKey); answ = deserializeTakt(redVal); } catch { } return answ; } #endregion #region metodi per PROD /// /// Esegue richieste lettura da PROD /// public static void procProdReadReq() { // !!!FIXME!!! } /// /// Esegue richieste lettura da PROD /// public static void procProdWriteReq() { // !!!FIXME!!! } /// /// Fornisce il prossimo TAKT da elaborare oppure null se non ce ne fossero altri da elaborare per la data CORRENTE /// /// public Takt prodGetNextTakt() { return null; } /// /// Chiave primo bunk su redis /// protected static string redFirstBunkKey = $"{redProdReq}:FirstBunk"; /// /// Chiave primo bunk su redis /// protected static string redAllNextBunkKey = $"{redProdReq}:NextBunk"; /// /// TTL standard x dati da scambiare con PROD (30 gg) /// protected static int ttlProdData = 3600 * 24 * 30; /// /// Chiave primo bunk su redis /// protected static string redNextBunkKey(int BunkID) { return $"{redProdReq}:NextBunk:{BunkID}"; } /// /// Resetto in REDIS i dati di bunk (corrente e successivi) /// public static void resetRedisBunkData() { redisFirstBunk = null; } /// /// Cache redis del PRIMO bunk da lavorare /// private static ProdBunk redisFirstBunk { get { ProdBunk answ = null; string rawData = memLayer.ML.getRSV(redFirstBunkKey); if (rawData != "") { // provo a deserializzare try { answ = JsonConvert.DeserializeObject(rawData); } catch { } } return answ; } set { if (value != null) { string redVal = JsonConvert.SerializeObject(value); // default lascio x 5 minuti... memLayer.ML.setRSV(redFirstBunkKey, redVal, ttlProdData); } else // se null elimino da redis { memLayer.ML.setRSV(redFirstBunkKey, ""); // elimino TUTTI i next... memLayer.ML.redFlushKey(redAllNextBunkKey); } } } /// /// Recupero da Redis del SUCCESSIVO bunk da lavorare /// /// /// private static ProdBunk getRedisNextBunk(int currBunkId) { ProdBunk answ = null; string rawData = memLayer.ML.getRSV(redNextBunkKey(currBunkId)); if (rawData != "") { // provo a deserializzare try { answ = JsonConvert.DeserializeObject(rawData); } catch { } } return answ; } /// /// Salvo in Redis il SUCCESSIVO bunk da lavorare /// /// /// private static void setRedisNextBunk(int currBunkId, ProdBunk value) { if (value != null) { string redVal = JsonConvert.SerializeObject(value); // default lascio x 5 minuti... memLayer.ML.setRSV(redNextBunkKey(currBunkId), redVal, ttlProdData); } else // se null elimino da redis { memLayer.ML.setRSV(redNextBunkKey(currBunkId), ""); } } /// /// Restituisce il PRIMO bunk secondo criterio: /// - posizione = 5 (ho letto da webApp il BUNK e preso in carico) /// - NumSheet > NumSheetUnload /// - Ordinato per StackIndex (crescente) x avere il più VECCHIO /// /// public static ProdBunk prodGetFirstBunk() { // cerco prima su REDIS... ProdBunk answ = redisFirstBunk; if (answ == null) { // vado sul DB e leggo ... DS_App.StackListDataTable tabBunks = DataLayer.man.taSTL.getLoaded(); // controllo di averne almeno 1... if (tabBunks.Count > 0) { DS_App.StackListRow currBunk = tabBunks[0]; answ = getBunkFromDb(currBunk); // se ho qualcosa salvo su REDIS redisFirstBunk = answ; } } return answ; } /// /// Restituisce il PROSSIMO bunk secondo criterio: /// - posizione = 5 (ho letto da webApp il BUNK e preso in carico) /// - NumSheet > NumSheetUnload /// - Ordinato per StackIndex (crescente) x avere il più VECCHIO /// - SUCCESSIVO al BunkID(=StackID) ricevuto /// /// public static ProdBunk prodGetNextBunk(int BunkID) { ProdBunk answ = getRedisNextBunk(BunkID); if (answ == null) { // vado sul DB e leggo ... DS_App.StackListDataTable tabBunks = DataLayer.man.taSTL.getLoaded(); // controllo di averne almeno 1... if (tabBunks.Count > 0) { DS_App.StackListRow currBunk = null; bool trovato = false; // ciclo foreach (var item in tabBunks) { if (trovato) { currBunk = item; break; } // controllo se sia quello richiesto if (item.StackID == BunkID) { trovato = true; } } // se c'è un bunk trovato --> carico if (currBunk != null) { answ = getBunkFromDb(currBunk); // salvo su redis setRedisNextBunk(BunkID, answ); } } } return answ; } /// /// Recupera e transcodifica DA DB i dati di UN SINGOLO bunk /// /// /// private static ProdBunk getBunkFromDb(DS_App.StackListRow currBunk) { ProdBunk answ; // calcolo attributi oggetti CStatus currSt = CStatus.Programmed; if (currBunk.Position == 5) { currSt = CStatus.Running; } else { currSt = CStatus.Done; } List elSheet = new List(); // recupero gli sheets di questo stack... DS_App.SheetListDataTable tabSheets = DataLayer.man.taSHL.getByStack(currBunk.StackID); DateTime dataStart = DateTime.Now; ProdSheet currPanel; foreach (var item in tabSheets) { // converto i workData con check null sul campo data WorkData wdPrint = new WorkData() { DtStart = item.IsPrntStartNull() ? null : (DateTime?)item.PrntStart, DtEnd = item.IsPrntEndNull() ? null : (DateTime?)item.PrntEnd, ProgramPath = item.PrintFilePath }; WorkData wdMachining = new WorkData() { DtStart = item.IsWrkStartNull() ? null : (DateTime?)item.WrkStart, DtEnd = item.IsWrkEndNull() ? null : (DateTime?)item.WrkEnd, ProgramPath = item.CncFilePath }; WorkData wdUnload = new WorkData() { DtStart = item.IsUnlStartNull() ? null : (DateTime?)item.UnlStart, DtEnd = item.IsUnlEndNull() ? null : (DateTime?)item.UnlEnd }; MaterialData material = new MaterialData() { MaterialId = item.MatID, MaterialDescription = item.MatDesc, MaterialPN = item.MatExtCode.ToString() }; PStatus currPnlStatus = PStatus.Programmed; Enum.TryParse(item.ShStatus.ToString(), out currPnlStatus); currPanel = new ProdSheet() { Printing = wdPrint, Machining = wdMachining, Unloading = wdUnload, Material = material, SheetId = item.SheetID, Status = currPnlStatus }; elSheet.Add(currPanel); if (!item.IsPrntStartNull()) { dataStart = item.PrntStart < dataStart ? item.PrntStart : dataStart; } } // compongo il bunk... answ = new ProdBunk() { BunkId = currBunk.StackID, Status = currSt, DataMatrix = currBunk.StackDtmx, SheetList = elSheet, DtStart = dataStart }; return answ; } /// /// Recupera e transcodifica DA DB i dati di UN SINGOLO bunk /// /// /// public static ProdBunk prodGetBunk(int StackID) { ProdBunk answ = null; List elSheet = new List(); var tabBunks = DataLayer.man.taSTL.getByKey(StackID); if (tabBunks.Count == 1) { DS_App.StackListRow currBunk = tabBunks[0]; // calcolo attributi oggetti CStatus currSt = CStatus.Programmed; if (currBunk.Position == 5) { currSt = CStatus.Running; } else { currSt = CStatus.Done; } // recupero gli sheets di questo stack... DS_App.SheetListDataTable tabSheets = DataLayer.man.taSHL.getByStack(StackID); DateTime dataStart = DateTime.Now; ProdSheet currPanel; foreach (var item in tabSheets) { // converto i workData WorkData wdPrint = new WorkData() { DtStart = item.IsPrntStartNull() ? null : (DateTime?)item.PrntStart, DtEnd = item.IsPrntEndNull() ? null : (DateTime?)item.PrntEnd, ProgramPath = item.PrintFilePath }; WorkData wdMachining = new WorkData() { DtStart = item.IsWrkStartNull() ? null : (DateTime?)item.WrkStart, DtEnd = item.IsWrkEndNull() ? null : (DateTime?)item.WrkEnd, ProgramPath = item.CncFilePath }; WorkData wdUnload = new WorkData() { DtStart = item.IsUnlStartNull() ? null : (DateTime?)item.UnlStart, DtEnd = item.IsUnlEndNull() ? null : (DateTime?)item.UnlEnd }; MaterialData material = new MaterialData() { MaterialId = item.MatID, MaterialDescription = item.MatDesc, MaterialPN = item.MatExtCode.ToString() }; PStatus currPnlStatus = PStatus.Programmed; Enum.TryParse(item.ShStatus.ToString(), out currPnlStatus); currPanel = new ProdSheet() { Printing = wdPrint, Machining = wdMachining, Unloading = wdUnload, Material = material, SheetId = item.StackID, Status = currPnlStatus }; elSheet.Add(currPanel); if (!item.IsPrntStartNull()) { dataStart = item.PrntStart < dataStart ? item.PrntStart : dataStart; } } // compongo il bunk... answ = new ProdBunk() { BunkId = currBunk.StackID, Status = currSt, DataMatrix = currBunk.StackDtmx, SheetList = elSheet, DtStart = dataStart }; } return answ; } /// /// Valore dello Stack correntemente in processing per ML (MachineLoad) /// public static string taktMLCurrStack { get { return memLayer.ML.getRSV(redMLCurrStack); } set { memLayer.ML.setRSV(redMLCurrStack, value); } } #endregion #region metodi x UNLOAD /// /// Calcola area REDIS per FOGLIO in fase di scarico /// /// /// public static string machineUnloadArea(int SheetID) { // se 0 --> tutto l'albero, sennò solo area corrente... string answ = ""; if (SheetID > 0) { answ = memLayer.ML.redHash($"MachineUnload:{SheetID}"); } else { answ = memLayer.ML.redHash($"MachineUnload"); } return answ; } /// /// Svuota elenco pezzi nella postazione di unload /// /// /// public bool resetSheetUnload(int SheetID = 0) { bool answ = false; try { memLayer.ML.redFlushKey(machineUnloadArea(SheetID)); answ = true; } catch { } return answ; } /// /// /// /// /// public static string getCurrentCss(int sheetID) { // area REDIS! string redKeyBase = $"{machineUnloadArea(sheetID)}"; // TTL standard int dataCacheTTL = memLayer.ML.cdvi("cssCacheTTL"); dataCacheTTL = dataCacheTTL <= 0 ? 60 : dataCacheTTL; // files string filename = HttpContext.Current.Server.MapPath("~/Content/SheetColor.css"); string answ = File.ReadAllText(filename); // elenco items da foglio!!! var tabItems = DataLayer.man.taIL.getBySheet(sheetID); List itemsAll = new List(); List itemsDepo = new List(); List itemsCart = new List(); List itemsBin = new List(); List itemsSecOp = new List(); //se ho items... if (tabItems.Count > 0) { // ciclo! foreach (var item in tabItems) { // aggiungoncomunque a lista generale... itemsAll.Add(item.ItemDtmx); // controllo SE sia stato depositato... check null su campo data if (!item.IsOnCartDateNull()) { itemsDepo.Add(item.ItemDtmx); } else if (item.ProcessesReq.Contains("PaintFlag")) { itemsBin.Add(item.ItemDtmx); } else { itemsCart.Add(item.ItemDtmx); } // controllo ANCHE postprocessing if (item.PostProcList != "") { itemsSecOp.Add(item.ItemDtmx); } } } // FIX BIN answ = updateCssByItemList(answ, redKeyBase, "ItemsBin", itemsBin, dataCacheTTL); // FIX CART answ = updateCssByItemList(answ, redKeyBase, "ItemsCart", itemsCart, dataCacheTTL); // FIX Scaricati answ = updateCssByItemList(answ, redKeyBase, "ItemsDepo", itemsDepo, dataCacheTTL); // FIX SEC-OP answ = updateCssByItemList(answ, redKeyBase, "ItemsSecOp", itemsSecOp, dataCacheTTL); // FIXED SEL da array oggetti selezionati... answ = updateCssByPickedItems(answ, redKeyBase, "ItemsSel", dataCacheTTL); #if false string rawData = memLayer.ML.getRSV($"{redKeyBase}:ItemsSel"); if (!string.IsNullOrEmpty(rawData)) { string replaceVal = ""; // deserializzo List selArray = JsonConvert.DeserializeObject>(rawData); // ciclo x cercare x ogni chiave (sessione utente) foreach (var item in selArray) { replaceVal += $"#{item},"; } if (replaceVal.Length > 1) { replaceVal = replaceVal.Remove(replaceVal.Length - 1); } // FIX CSS! answ = answ.Replace("#ItemsSel", replaceVal); replaceVal = ""; } #endif // INFINE serializzo e salvo tutti gli items trovati... string serVal = JsonConvert.SerializeObject(itemsAll); memLayer.ML.setRSV($"{redKeyBase}:ItemsAll", serVal, dataCacheTTL); // salvo redis css! memLayer.ML.setRSV($"{redKeyBase}:Css", answ, dataCacheTTL); return answ; } /// /// Registra che un dato ITEM è stato prelevato in fase di scarico da ID foglio + datamatrix /// /// ID foglio /// Cod del device di scarico /// Cod datamatrix ITEM /// public static bool saveItemPickup(int sheetID, string deviceId, string itemDtmx) { // area REDIS! string redKeyBase = $"{machineUnloadArea(sheetID)}"; bool answ = false; string rawData = memLayer.ML.getRSV($"{redKeyBase}:ItemsSel"); Dictionary dictData = new Dictionary(); if (!string.IsNullOrEmpty(rawData)) { dictData = JsonConvert.DeserializeObject>(rawData); } try { // cerco chiave device... if (dictData.ContainsKey(deviceId)) { // sostituisco dictData[deviceId] = itemDtmx; } else { dictData.Add(deviceId, itemDtmx); } // salvo! rawData = JsonConvert.SerializeObject(dictData); memLayer.ML.setRSV($"{redKeyBase}:ItemsSel", rawData); answ = true; // reset memoria redis del CSS x obbligare refresh... memLayer.ML.setRSV($"{redKeyBase}:Css", ""); } catch { } return answ; } /// /// Registra che un dato ITEM è stato prelevato in fase di scarico da ID foglio + datamatrix /// /// ID foglio /// Cod del device di scarico /// public static bool resetItemPickup(int sheetID, string deviceId) { // area REDIS! string redKeyBase = $"{machineUnloadArea(sheetID)}"; bool answ = false; string rawData = memLayer.ML.getRSV($"{redKeyBase}:ItemsSel"); if (!string.IsNullOrEmpty(rawData)) { try { Dictionary dictData = JsonConvert.DeserializeObject>(rawData); // cerco chiave device... if (dictData.ContainsKey(deviceId)) { // sostituisco dictData.Remove(deviceId); } answ = true; } catch { } } return answ; } /// /// Processa elenco items e salva in redis valori x css, elenchi, ... /// /// CSS corrente /// HASH abse x area REDIS /// nome variabile x elenco items /// Elenco items specifici /// TTL della cache x salvataggio valori /// public static string updateCssByItemList(string currCss, string redKeyBase, string varName, List itemList, int dataCacheTTL) { string replaceVal = ""; if (itemList.Count > 0) { foreach (var item in itemList) { replaceVal += $"#{item},"; } if (replaceVal.Length > 1) { replaceVal = replaceVal.Remove(replaceVal.Length - 1); } // FIX CSS! currCss = currCss.Replace($"#{varName}", replaceVal); //serializzo e salvo string serVal = JsonConvert.SerializeObject(itemList); memLayer.ML.setRSV($"{redKeyBase}:{varName}", serVal, dataCacheTTL); } return currCss; } /// /// Processa elenco items e salva in redis valori x css, elenchi, ... /// /// CSS corrente /// HASH abse x area REDIS /// nome variabile x elenco items /// TTL della cache x salvataggio valori /// public static string updateCssByPickedItems(string currCss, string redKeyBase, string varName, int dataCacheTTL) { string replaceVal = ""; string rawData = memLayer.ML.getRSV($"{redKeyBase}:ItemsSel"); if (!string.IsNullOrEmpty(rawData)) { try { Dictionary dictData = JsonConvert.DeserializeObject>(rawData); // ciclo x cercare x ogni chiave (sessione utente) foreach (var item in dictData) { replaceVal += $"#{item.Value},"; } if (replaceVal.Length > 1) { replaceVal = replaceVal.Remove(replaceVal.Length - 1); } // FIX CSS! currCss = currCss.Replace("#ItemsSel", replaceVal); } catch { } } return currCss; } #endregion } }