using MongoDB.Driver; using Newtonsoft.Json; using NKC_SDK; using SteamWare; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.NetworkInformation; using System.Threading; using System.Web; namespace AppData { /// /// Classe con metodi di supporto per COMUNICAZIONE /// public class ComLib { #region Public Fields /// /// Classe impiego sstatico ComLib... /// public static ComLib man = new ComLib(); public static string redBatchDescend = "NKC:SERV:BATCHDESCEND"; public static string redKits = "NKC:SERV:KITS"; public static string redMachUnloadCount = "NKC:SERV:MACH_UNLOAD:COUNT"; public static string redMachUnloadForce = "NKC:SERV:MACH_UNLOAD:FORCERELOAD"; public static string redMLCurrBunk = "NKC:SERV:TAKT:CurrBunk"; public static string redMsgCount = "NKC:SERV:BREQ:MCount"; public static string redMsgList = "NKC:SERV:BREQ:MList"; public static string redNestAnsw = "NKC:NEST:BANSW"; public static string redOrders = "NKC:SERV:ORDERS"; public static string redOutPath = "NKC:SERV:BREQ"; public static string redProdAnsw = "NKC:PROD:BUNKS"; public static string redProdMachClock = "NKC:PROD:MACH:CLOCK"; public static string redProdMachList = "NKC:PROD:MACH:LIST"; public static string redProdMachStateData = "NKC:PROD:MACH:STATE"; public static string redProdMachStateLive = "NKC:PROD:MACH:LIVE"; public static string redProdReq = "NKC:SERV:BUNKS"; public static string redProdStatDec = "NKC:PROD:MACH:STATDEC"; /// /// chaive redis x cache conteggio coda PJQ /// public static string redQueueCount = "NKC:SERV:PJQ"; /// /// chaive redis x cache conteggio coda PJQ composta da tante code /// public static string redQueueCountSet = "NKC:SERV:PJQCOUNT"; /// /// Richiesta sec screen /// public static string redSecScreenReq = "NKC:SECSCREEN:REQ"; /// /// Vato ricalcolo dati stats giornalieri /// public static string redVetoDayStats = "NKC:SERV:DAYSTATS:RECALC"; #endregion Public Fields #region Public Constructors /// /// Init classe ComLib /// public ComLib() { database = memLayer.ML.getMongoDatabase("NKC"); } #endregion Public Constructors #region Public Properties /// /// verifica se sia avviabile un nuovo task nesting controllando cache Redis o tabelle batch/offlineOrders /// public static bool canStartNew { get { DataLayer DLMan = new DataLayer(); bool answ = false; bool valido = false; // cerco in redis if (memLayer.ML.redKeyPresent(canStartNewKey)) { string rawData = memLayer.ML.getRSV(canStartNewKey); valido = bool.TryParse(rawData, out answ); } if (!valido) { // in primis controllo SE ci siano task running, nel qual caso è false e basta... int numEst = DLMan.taBL.getByStatus((int)BatchStatus.EstimationRequested, "", true, 0).Count; int numNest = DLMan.taBL.getByStatus((int)BatchStatus.NestRequested, "", true, 0).Count; // ora controllo anche offline orders... int numOffOrd = DLMan.taOffOL.getRunning().Count; // ora la somma di tutti DEVE essere zero... answ = ((numEst + numNest + numOffOrd) == 0); // salvo in redis memLayer.ML.setRSV(canStartNewKey, answ.ToString(), 2); } return answ; } } public static string canStartNewKey { get { return $"{redOutPath}:CanStartNew"; } } /// /// 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 string currBatchReqKey { get { return $"{redOutPath}:CURR"; } } public static DS_App.StatusDecodeDataTable TabStatusDec { get { DS_App.StatusDecodeDataTable tabStaDec = new DS_App.StatusDecodeDataTable(); // cerco in Redis... string rawData = memLayer.ML.getRSV(redProdStatDec); // provo a deserializzare e cercare... if (!string.IsNullOrEmpty(rawData)) { tabStaDec = JsonConvert.DeserializeObject(rawData); } else { } return tabStaDec; } set { string rawData = JsonConvert.SerializeObject(value); memLayer.ML.setRSV(redProdStatDec, rawData, 600); } } /// /// ID del BUNK correntemente in processing per ML (MachineLoad) /// public static string taktMLCurrBunk { get { return memLayer.ML.getRSV(redMLCurrBunk); } set { memLayer.ML.setRSV(redMLCurrBunk, value); } } #endregion Public Properties #region Public Methods /// /// Aggiorna revisione indice sheet x BUNK (cambio foglio) /// /// /// public static long advaceSheetRevByBunk(int BunkID) { long answ = 0; if (BunkID > 0) { // recupero da REDIS! string redKeyExp = memLayer.ML.redHash($"DataExp"); string redKeyRev = $"{ComLib.machineUnloadBunkArea(BunkID)}:Rev"; // incremento... answ = memLayer.ML.setRCntI(redKeyRev); // se > 999 --> resetto if (answ > 999) { memLayer.ML.resetRCnt(redKeyRev); } } return answ; } /// /// Elenco dei Batch descendant di un batch ancestor /// public static DS_App.BatchListDataTable BatchDescendant(int BatchId) { DataLayer DLMan = new DataLayer(); string redKey = $"{redBatchDescend}:{BatchId}"; string rawData = ""; DS_App.BatchListDataTable answ = new DS_App.BatchListDataTable(); // cerco in redis if (memLayer.ML.redKeyPresent(redKey)) { rawData = memLayer.ML.getRSV(redKey); if (!string.IsNullOrEmpty(rawData)) { try { answ = JsonConvert.DeserializeObject(rawData); } catch { } } } // se vuoto rileggo if (answ.Count == 0) { answ = DLMan.taBL.getDescendByKey(BatchId); // salvo in cache rawData = JsonConvert.SerializeObject(answ); //memLayer.ML.setRSV(redKey, rawData, 5 * 60); // memoria brevissima... memLayer.ML.setRSV(redKey, rawData, 5); } return answ; } /// /// Elenco dei Batch descendant di un batch a sua volta descendant /// public static DS_App.BatchListDataTable BatchOtherDescendant(int BatchDescId) { DataLayer DLMan = new DataLayer(); string redKey = $"{redBatchDescend}:{BatchDescId}"; string rawData = ""; DS_App.BatchListDataTable answ = new DS_App.BatchListDataTable(); // cerco in redis if (memLayer.ML.redKeyPresent(redKey)) { rawData = memLayer.ML.getRSV(redKey); if (!string.IsNullOrEmpty(rawData)) { try { answ = JsonConvert.DeserializeObject(rawData); } catch { } } } // se vuoto rileggo if (answ.Count == 0) { answ = DLMan.taBL.getSplitByKey(BatchDescId); // salvo in cache rawData = JsonConvert.SerializeObject(answ); //memLayer.ML.setRSV(redKey, rawData, 5 * 60); // memoria brevissima... memLayer.ML.setRSV(redKey, rawData, 5); } 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 = traduci("Imported"); break; case BatchStatus.EstimationRequested: answ = traduci("EstimationRequested"); break; case BatchStatus.EstimationDone: answ = traduci("EstimationCompleted"); break; case BatchStatus.NestRequested: answ = traduci("NestingRequested"); break; case BatchStatus.NestDone: answ = traduci("NestingCompleted"); break; case BatchStatus.Approved: answ = traduci("NestingApproved"); break; case BatchStatus.Discarded: answ = traduci("NestingDiscarded"); break; case BatchStatus.Errors: answ = traduci("NestingPrelimErrors"); break; case BatchStatus.PartEval: answ = traduci("NestPartEvaluating"); break; case BatchStatus.PartOk: answ = traduci("NestPartValidated"); break; case BatchStatus.PartKo: answ = traduci("NestPartNotValidated"); break; case BatchStatus.ErrorsOnEstim: answ = traduci("ErrorsOnEstim"); break; case BatchStatus.ErrorsOnNesting: answ = traduci("ErrorsOnNesting"); break; default: answ = traduci("NestStateUnk"); break; } } catch { } return answ; } /// /// Stato batch (bozza/stima/nesting...) /// /// /// public static BatchStatus BStatus(int BatchId) { DataLayer DLMan = new DataLayer(); BatchStatus answ = BatchStatus.Imported; DS_App.BatchListDataTable tabBatch = DLMan.taBL.getByKey(BatchId); if (tabBatch != null && tabBatch.Count > 0) { try { // mostro split se di tipo 1... answ = (BatchStatus)tabBatch[0].STATUS; } catch { } } return answ; } /// /// Tipo batch tra ancestor/descendant /// /// /// public static BatchType BType(int BatchId) { DataLayer DLMan = new DataLayer(); BatchType answ = BatchType.Original; DS_App.BatchListDataTable tabBatch = DLMan.taBL.getByKey(BatchId); if (tabBatch != null && tabBatch.Count > 0) { try { // mostro split se di tipo 1... answ = (BatchType)tabBatch[0].BatchType; } catch { } } 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; // 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) { DataLayer DLMan = new DataLayer(); 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 drawing if (!string.IsNullOrEmpty(offOrder.DrawingPath)) { DLMan.taOffOL.updateDrawing(OffOrderID, offOrder.DrawingPath, offOrder.CncPath); } } // restituisco ok return answ; } /// /// Verifica esistenza del PDF SE presente negli optParams /// - OK SE NON c'è parametro x pdf /// - OK SE presente parametro --> cerca il file --> lo trova /// /// Part da analizzare /// Path del file PDF analizzato /// public static bool checkPdfExistAccessible(Part reqPart, out string pdfPath) { pdfPath = getPdfFilePath(reqPart.OptParameters); bool answ = string.IsNullOrEmpty(pdfPath); if (!answ) { try { string parentDir = Path.GetDirectoryName(pdfPath); bool shareOk = true; bool dirOk = true; if (IsUnc(parentDir)) { string pathRoot = Path.GetPathRoot(parentDir); Uri newUri = new Uri(pathRoot); // tento PING PingReply pingResult = NKC.testPingDevice(newUri.Host); shareOk = (pingResult.Status == IPStatus.Success); } if (shareOk) { dirOk = Directory.Exists(parentDir); if (dirOk) { answ = File.Exists(pdfPath); } } } catch { } } return answ; } /// /// Invia una richiesta di esecuzione di Nesting x un Batch ANCESTOR /// /// Batch di cui si chiede processing /// public static bool checkSendBatchSplit(int BatchID) { string logIdKey = $"checkSendBatchSplit | BatchID: {BatchID} |"; int nextIndex = 10; bool batchSent = false; bool batchProcessed = false; DataLayer DLMan = new DataLayer(); var currType = ComLib.BType(BatchID); // log tipo di batch Log.Instance.Info($"{logIdKey} | Batch currType: {currType}"); // NKC2: controllo SE sia un batch tipo ancestor (1° invio) if (currType == BatchType.Ancestor) { Log.Instance.Info($"{logIdKey} | Batch Ancestor | 01"); // recupero batch descendant var tabDesc = ComLib.BatchDescendant(BatchID); if (tabDesc != null && tabDesc.Count > 0) { batchSent = false; // ciclo fino a trovare un batch VALIDO (= contiene ordini) foreach (var item in tabDesc) { batchProcessed = false; // 2021.07.19 FIX x caso batch vuoto: se non ho pezzi --> approvo // direttamente e passo al successivo... var tabItems = DLMan.taIL.getByBatch(item.BatchID); if (tabItems != null) { // calcolo idx da nome macchina... string placeCod = item.PlaceCod; if (!string.IsNullOrEmpty(placeCod) && placeCod.Contains("NE")) { int neIdx = 1; int.TryParse(placeCod.Replace("NE", ""), out neIdx); nextIndex = 10 + 50 * (neIdx - 1); } // --> invio batch if (tabItems.Count > 0) { // primo parto da indice 10... ComLib.sendBatchReq(item.BatchID, "Nesting", 2, false, nextIndex, false); // registro su DB nesting iniziato... DLMan.taBL.updateStatus(item.BatchID, (int)BatchStatus.NestRequested, "", -1); batchProcessed = true; batchSent = true; } } //--> approvo direttamente e passo al successivo... (annullo batch) if (!batchProcessed) { // registro su DB batch DISCARDED (NON HA PEZZI...) DLMan.taBL.updateStatus(item.BatchID, (int)BatchStatus.Discarded, "", -1); } // se ho fatto --> esco if (batchSent) break; } } Log.Instance.Info($"{logIdKey} | Batch Ancestor | 02"); } // NKC2: se è un batch ti dipo descendant (invii successivi) if (currType == BatchType.Descendant) { Log.Instance.Info($"{logIdKey} | Batch Descendant | 01"); // verifico se ce ne siano altri NON validati (ma splitted) var tabDesc = ComLib.BatchOtherDescendant(BatchID); if (tabDesc != null && tabDesc.Count > 0) { batchSent = false; // ciclo x tutte le righe che NON fossero con nesting effettuato foreach (var item in tabDesc) { batchProcessed = false; // se c'è qualcosa da processare lo richiede if (item.STATUS == 2) { nextIndex += 50; Log.Instance.Info($"{logIdKey} | Batch Descendant | PlaceCod: {item.PlaceCod} | Takt: {item.Takt} | nextIndex: {nextIndex}"); // 2021.07.19 FIX x caso batch vuoto: se non ho pezzi --> approvo // direttamente e passo al successivo... var tabItems = DLMan.taIL.getByBatch(item.BatchID); if (tabItems != null) { // calcolo idx da nome macchina... string placeCod = item.PlaceCod; if (!string.IsNullOrEmpty(placeCod) && placeCod.Contains("NE")) { int neIdx = 1; int.TryParse(placeCod.Replace("NE", ""), out neIdx); nextIndex = 10 + 50 * (neIdx - 1); } // --> invio batch if (tabItems.Count > 0) { ComLib.sendBatchReq(item.BatchID, "Nesting", 2, false, nextIndex, false); // registro su DB nesting iniziato... DLMan.taBL.updateStatus(item.BatchID, (int)BatchStatus.NestRequested, "", -1); batchProcessed = true; batchSent = true; } } //--> approvo direttamente e passo al successivo... (annullo batch) if (!batchProcessed) { // registro su DB batch DISCARDED (NON HA PEZZI...) DLMan.taBL.updateStatus(item.BatchID, (int)BatchStatus.Discarded, "", -1); } // se ho fatto --> esco if (batchSent) break; } // se non ha trovato nulla --> prova update Batch Ancestor... } } Log.Instance.Info($"{logIdKey} | Batch Descendant | 02"); } Log.Instance.Info($"{logIdKey} | Batch test result: {batchSent}"); return batchSent; } /// /// verifica che lo status e la decodifica ci siano... /// /// public static DS_App.StatusDecodeRow checkStationDecode(string station, string code) { DataLayer DLMan = new DataLayer(); var currTab = TabStatusDec; // cerco item DS_App.StatusDecodeRow foundItem = currTab.Where(x => x.Station == station && x.Code == code).FirstOrDefault(); if (foundItem == null) { // forzo (ri)lettura... currTab = DLMan.taStatDec.GetData(); TabStatusDec = currTab; // cerco di nuovo item foundItem = currTab.Where(x => x.Station == station && x.Code == code).FirstOrDefault(); } if (foundItem == null) { // se non ci fosse --> creo DLMan.taStatDec.insert(station, code); // inserisco empty x 1 sec così rileggerà... memLayer.ML.setRSV(redProdStatDec, "", 1); // rileggo currTab = TabStatusDec; foundItem = currTab.Where(x => x.Station == station && x.Code == code).FirstOrDefault(); } return foundItem; } /// /// Elimina da MongoDb info envelope fino al valore idx2keep indicato /// /// Valore da lasciare/non eliminare /// public static int CleanupMongo(long idx2keep) { // contatore eliminazioni int numDel = 0; // inizio recuperando da HashList var currList = getEnvList(); // riordino x chiave x fare prima... var ordList = currList.OrderBy(x => x.Key).ToList(); // ciclo! int zIdx = 0; foreach (var item in ordList) { if (int.TryParse(item.Key.Substring(1), out zIdx)) { // per ogni valore controllo se sia < di quello richiesto if (zIdx < idx2keep) { ComLib.man.MongoDeleteEnvData(item.Key); // conteggio eliminati numDel++; } else { break; } } } // ritorno return numDel; } /// /// Elimina da Redis info envelope fino al valore idx2keep indicato /// /// Valore da lasciare/non eliminare /// public static int CleanupRedis(long idx2keep) { // contatore eliminazioni int numDel = 0; // inizio recuperando da HashList var currList = getEnvList(); // riordino x chiave x fare prima... var ordList = currList.OrderBy(x => x.Key).ToList(); // ciclo! int zIdx = 0; string redZKey = ""; foreach (var item in ordList) { if (int.TryParse(item.Key.Substring(1), out zIdx)) { // per ogni valore controllo se sia < di quello richiesto if (zIdx < idx2keep) { // elimino cache redZKey = $"{redOutPath}:{item.Key}"; memLayer.ML.redDelKey(redZKey); // elimino chiave in hashList memLayer.ML.redDelHashField(redMsgList, item.Key); // conteggio eliminati numDel++; } else { break; } } } // ritorno conteggio eliminazioni return numDel; } /// /// Deserializza un ordine offline /// /// /// public static nestReplyOffOrd deserializeOfflineOrder(string rawData) { nestReplyOffOrd answ = null; try { answ = JsonConvert.DeserializeObject(rawData); } catch { } return answ; } /// /// Helper x deserializzare l'oggetto /// /// /// public static Takt deserializeTakt(string rawData) { Takt answ = JsonConvert.DeserializeObject(rawData); return answ; } /// /// Cache redis del BunkID in lavorazione sulla macchina /// public static int getCurrBatchId(string macchina) { int answ = -1; string rawData = memLayer.ML.getRSV(redCurrBatchId(macchina)); int.TryParse(rawData, out answ); return answ; } /// /// BUNK corrente (x ora copia di first, poi sarà quello SELEZIONATO tra quelli SELEZIONABILI) /// /// public static DS_App.StackListRow getCurrBunk(string machine = "WRK001") { DS_App.StackListRow answ = null; DS_App.StackListDataTable tabBunk = null; DataLayer DLMan = new DataLayer(); // cerco in cache.... if (getCurrBunkTab(machine) != null) { tabBunk = getCurrBunkTab(machine); } else { tabBunk = DLMan.taSTL.getLoaded(machine); // salvo in redis setCurrBunkTab(machine, tabBunk); } if (tabBunk != null && tabBunk.Count > 0) { answ = tabBunk[0]; } return answ; } /// /// Cache redis del BunkID in lavorazione sulla macchina /// public static int getCurrBunkId(string macchina) { int answ = -1; string rawData = memLayer.ML.getRSV(redCurrBunkId(macchina)); int.TryParse(rawData, out answ); return answ; } /// /// /// /// public static string getCurrentCss(int sheetID) { DataLayer DLMan = new DataLayer(); // 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); // solo se sheet > 0... if (sheetID > 0) { try { // elenco items da foglio!!! var tabItems = DLMan.taIL.getBySheet(sheetID); List itemsAll = new List(); List itemsDepo = new List(); List itemsCart = new List(); List itemsBin = new List(); List itemsSecOp = new List(); List itemsScrap = new List(); List itemsSelect = 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 SCRAP if (item.StatusID >= 990) { itemsScrap.Add(item.ItemDtmx); } // controllo SE sia stato depositato... check status 3/4 else if (item.StatusID == 3 || item.StatusID == 4) { 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); } // se selezionato status 2... if (item.StatusID == 2) { itemsSelect.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); // FIX SCRAP answ = updateCssByItemList(answ, redKeyBase, "ItemsScrap", itemsScrap, dataCacheTTL); // FIXED SEL da array oggetti selezionati... answ = updateCssByItemList(answ, redKeyBase, "ItemsSel", itemsSelect, dataCacheTTL); //answ = updateCssByPickedItems(answ, redKeyBase, "ItemsSel", dataCacheTTL); // 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); } catch { } } return answ; } /// /// Restituisce il codice di envelope ultimo impiegato /// /// public static long GetCurrMCount() { // incremento counter long nextIndex = memLayer.ML.getRCnt(redMsgCount); // ritorno return nextIndex; } /// /// PackList corrente (running in KIT) /// /// public static DS_App.PackListRow getCurrPackList() { DataLayer DLMan = new DataLayer(); DS_App.PackListRow answ = null; var tabPLD = DLMan.taPL.getRunning(); if (tabPLD.Count > 0) { answ = tabPLD[0]; } return answ; } /// /// Recupera lo sheet corrente da un BUNK come quello in status 5... /// /// /// /// public static DS_App.SheetListRow getCurrSheet(int BatchID, string machine) { DS_App.SheetListRow answ = null; if (BatchID > 0 && !string.IsNullOrEmpty(machine)) { try { DS_App.SheetListDataTable tabSheets = null; // cerco in cache.... if (getCurrSheetTab(machine) != null) { tabSheets = getCurrSheetTab(machine); } else { // 2023.10.27 passaggio versione cached #if false // recupero sheet corrente da Bunk... DataLayer DLMan = new DataLayer(); tabSheets = DLMan.taSHL.getByMLStatus(BatchID, 5, 5, machine); #endif tabSheets = SheetTabGet(machine, BatchID, 5, 5); // salvo in redis setCurrSheetTab(machine, tabSheets); } // leggo prima riga --> foglio corrente if (tabSheets != null && tabSheets.Count > 0) { answ = tabSheets[0]; } } catch { } } return answ; } /// /// Cache redis del SheetID in lavorazione sulla macchina /// public static int getCurrSheetId(string macchina) { int answ = -1; string rawData = memLayer.ML.getRSV(redCurrSheetId(macchina)); int.TryParse(rawData, out answ); 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; } /// /// IP del device /// /// public static string GetIPAddress() { HttpContext context = HttpContext.Current; string ipAddress = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (!string.IsNullOrEmpty(ipAddress)) { string[] addresses = ipAddress.Split(','); if (addresses.Length != 0) { return addresses[0]; } } return context.Request.ServerVariables["REMOTE_ADDR"]; } public static bool getMachLiveStatus(string machine) { bool isLive = false; /// cerco in redis... string redKey = $"{redProdMachStateLive}:{machine}"; string redVal = memLayer.ML.getRSV(redKey); if (!string.IsNullOrEmpty(redVal)) { bool.TryParse(redVal, out isLive); } return isLive; } /// /// 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; } /// /// Recupera file pdf /// /// /// public static string getPdfFilePath(Dictionary optParameters) { string answ = ""; if (optParameters.ContainsKey("PdfLink")) { answ = optParameters["PdfLink"]; } return answ; } /// /// 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; } public static int getSecScreenCode() { int answ = 0; Random rnd = new Random(); answ = rnd.Next(1000000); return answ; } /// /// Restitusice il path del PDF richiesto su una data SecScreen come salvato su REDIS /// /// cod schermo, formato SSC000000 /// public static string getSecScreenRequest(string secScreenCode) { string answ = ""; // recupero ultima call string redKey = $"{redSecScreenReq}:{secScreenCode}"; answ = memLayer.ML.getRSV(redKey); return answ; } /// /// Recupera da REDIS info indice revisione x BUNK (cambio foglio) /// /// /// public static int getSheetRevByBunk(int BunkID) { int answ = 0; if (BunkID > 0) { // recupero da REDIS! string redKeyExp = memLayer.ML.redHash($"DataExp"); string redKeyRev = $"{ComLib.machineUnloadBunkArea(BunkID)}:Rev"; // controllo expiry globale... se manca SVUOTO area string rawData = memLayer.ML.getRSV(redKeyExp); if (string.IsNullOrEmpty(rawData)) { // svuoto e scrivo... memLayer.ML.redFlushKey(memLayer.ML.redHash($"MachineUnload")); memLayer.ML.redFlushKey(memLayer.ML.redHash($"TabSheets")); memLayer.ML.setRSV(redKeyExp, $"Reload Data {DateTime.Now}", 3600); } answ = memLayer.ML.getRCnt(redKeyRev); } return answ; } public static bool IsUnc(string path) { string root = Path.GetPathRoot(path); // Check if root starts with "\\", clearly an UNC if (root.StartsWith(@"\\")) return true; // Check if the drive is a network drive DriveInfo drive = new DriveInfo(root); if (drive.DriveType == DriveType.Network) return true; return false; } /// /// Elenco dei kit dato Batch (specifico) /// /// /// public static DS_App.KitListDataTable KitListByBatch(int BatchId) { DS_App.KitListDataTable answ = new DS_App.KitListDataTable(); if (BatchId > 0) { DataLayer DLMan = new DataLayer(); string redKey = $"{redKits}:ByBatch:{BatchId}"; string rawData = ""; // cerco in redis if (memLayer.ML.redKeyPresent(redKey)) { rawData = memLayer.ML.getRSV(redKey); if (!string.IsNullOrEmpty(rawData)) { try { answ = JsonConvert.DeserializeObject(rawData); } catch { } } } // se vuoto rileggo if (answ.Count == 0) { // recupero ordini dato il batch MAIN answ = DLMan.taKL.getByBatch(BatchId); // salvo in cache rawData = JsonConvert.SerializeObject(answ); memLayer.ML.setRSV(redKey, rawData, 5); } } 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; } /// /// Calcola area REDIS per MACCHINA /// /// /// public static string machineArea(string machineCod) { string answ = memLayer.ML.redHash($"currMachineData:{machineCod}"); return answ; } /// /// 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; } /// /// Calcola area REDIS per BUNK in fase di scarico /// /// /// public static string machineUnloadBunkArea(int BunkID) { // se 0 --> tutto l'albero, sennò solo area corrente... string answ = ""; if (BunkID > 0) { answ = memLayer.ML.redHash($"MachineUnload:Bunk:{BunkID}"); } else { answ = memLayer.ML.redHash($"MachineUnload:Bunk"); } return answ; } /// /// Elenco degli orders dato Batch (specifico) /// /// /// public static DS_App.OrderListTreeDataTable OrdersExtByBatch(int BatchId) { DS_App.OrderListTreeDataTable answ = new DS_App.OrderListTreeDataTable(); if (BatchId > 0) { DataLayer DLMan = new DataLayer(); string redKey = $"{redOrders}:ByBatch:{BatchId}"; string rawData = ""; // cerco in redis if (memLayer.ML.redKeyPresent(redKey)) { rawData = memLayer.ML.getRSV(redKey); if (!string.IsNullOrEmpty(rawData)) { try { answ = JsonConvert.DeserializeObject(rawData); } catch { } } } // se vuoto rileggo if (answ.Count == 0) { // recupero ordini dato il batch MAIN answ = DLMan.taOLT.getByBatch(BatchId); // salvo in cache rawData = JsonConvert.SerializeObject(answ); memLayer.ML.setRSV(redKey, rawData, 5); } } return answ; } /// /// Elenco degli orders dato Batch (Ancestor/Principale) /// /// /// public static DS_App.OrderListTreeDataTable OrdersExtByBatchTree(int BatchId) { DS_App.OrderListTreeDataTable answ = new DS_App.OrderListTreeDataTable(); if (BatchId > 0) { DataLayer DLMan = new DataLayer(); string redKey = $"{redOrders}:ByBatchTree:{BatchId}"; string rawData = ""; // cerco in redis if (memLayer.ML.redKeyPresent(redKey)) { rawData = memLayer.ML.getRSV(redKey); if (!string.IsNullOrEmpty(rawData)) { try { answ = JsonConvert.DeserializeObject(rawData); } catch { } } } // se vuoto rileggo if (answ.Count == 0) { // recupero ordini dato il batch MAIN answ = DLMan.taOLT.getByBatchTree(BatchId); // salvo in cache rawData = JsonConvert.SerializeObject(answ); memLayer.ML.setRSV(redKey, rawData, 10); } } return answ; } /// /// Reset cache ordini EXT /// public static void OrdersExtResetCache() { string redKey = $"{redOrders}:ByBatch:*"; memLayer.ML.redFlushKey(redKey); redKey = $"{redOrders}:ByBatchTree:*"; memLayer.ML.redFlushKey(redKey); redKey = $"{redKits}:ByBatch:*"; memLayer.ML.redFlushKey(redKey); } 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; case BatchPosition.Current: answ = traduci("BatchCurrent"); break; case BatchPosition.Completed: answ = traduci("BatchCompleted"); break; default: break; } } catch { } return answ; } /// /// Esegue richieste lettura da PROD /// public static void procProdReadReq() { // !!!FIXME!!! } /// /// Esegue richieste scrittura da PROD /// public static void procProdWriteReq() { // !!!FIXME!!! } /// /// Recupera e transcodifica DA DB i dati di UN SINGOLO bunk /// /// /// /// public static ProdBunk prodGetBunk(int StackID, string machine) { DataLayer DLMan = new DataLayer(); ProdBunk answ = null; List elSheet = new List(); var tabBunks = DLMan.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 = DLMan.taSHL.getByStack(StackID, machine); DateTime dataStart = DateTime.Now; ProdSheet currPanel; string nestBasePath = memLayer.ML.CRS("nestBasePath").ToLower(); string servBasePath = memLayer.ML.CRS("servBasePath").ToLower(); string prodBasePath = memLayer.ML.CRS("prodBasePath").ToLower(); 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.ToLower().Replace(nestBasePath, prodBasePath).Replace(servBasePath, prodBasePath) }; WorkData wdMachining = new WorkData() { DtStart = item.IsWrkStartNull() ? null : (DateTime?)item.WrkStart, DtEnd = item.IsWrkEndNull() ? null : (DateTime?)item.WrkEnd, ProgramPath = item.CncFilePath.ToLower().Replace(nestBasePath, prodBasePath).Replace(servBasePath, prodBasePath) }; 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; } /// /// Restituisce il BUNK che è il primo della lista x la MACCHINA indicata: /// - posizione = 3 (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(string machine) { DataLayer DLMan = new DataLayer(); // cerco prima su REDIS... ProdBunk answ = redisFirstBunk; if (answ == null) { // vado sul DB e leggo ... DS_App.StackListDataTable tabBunks = DLMan.taSTL.getLoaded(machine); // controllo di averne almeno 1... if (tabBunks.Count > 0) { DS_App.StackListRow currBunk = tabBunks[0]; answ = getBunkFromDb(currBunk, machine); // se ho qualcosa salvo su REDIS redisFirstBunk = answ; } } return answ; } /// /// Restituisce il PROSSIMO bunk x la MACCHINA indicata 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, string machine) { DataLayer DLMan = new DataLayer(); ProdBunk answ = getRedisNextBunk(BunkID); if (answ == null) { // vado sul DB e leggo ... DS_App.StackListDataTable tabBunks = DLMan.taSTL.getLoaded(machine); // 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, machine); // salvo su redis setRedisNextBunk(BunkID, answ); } } } return answ; } /// /// Elenco di sheet in lavorazione su una data macchina: /// - da macchina recupera il BATCH /// - dal batch prende i BUNK CARICATI sulla macchina (posizione 5) /// - filtra i fogli già lavorati /// /// /// public static SheetWorkList prodGetSheetWorkList(string codPost) { DataLayer DLMan = new DataLayer(); // init out SheetWorkList answ = null; // recupero batch corrente DS_App.BatchListDataTable currBatch = DLMan.taBL.getCurrentByMachine(codPost); try { if (currBatch != null) { // come batch DOVREI averne solo 1 in corso... DS_App.BatchListRow batchRow = currBatch[0]; // recupero i vari SHEETS del batch... DS_App.SheetListDataTable sheetTable = DLMan.taSHL.getCurrentByBatch(batchRow.BatchID, codPost); List sheetList = new List(); // controllo che SIA NULL la data di unload --> NON ancora scaricato foreach (var item in sheetTable) { // metto in elenco SOLO se NON nulla data fine unload if (item.IsUnlEndNull()) { sheetList.Add(item); } } answ = convertSheetWorkList(sheetList); } } catch { } return answ; } /// /// Restituisce stato macchina (da Redis) /// /// public static MachineStatData prodMachStateDataGet(string machine) { MachineStatData answ = new MachineStatData(); string redVal = memLayer.ML.getRSV($"{redProdMachStateData}:{machine}"); if (!string.IsNullOrEmpty(redVal)) { answ = JsonConvert.DeserializeObject(redVal); } return answ; } /// /// Salva gli stati macchina ricevuti sul DB e poi salva ultimo su redis Do x scontato tutti /// singola macchina /// /// public static bool prodMachStateDataInsert(MachineStatData updateRecords) { /* ------------------------------------------------------------------ * Info preliminari * Public Const STATION_LINE As String = "LINE" * Public Const STATION_PRINTER As String = "PRINTER" * Public Const STATION_NC_MACHINE As String = "NC_MACHINE" * Public Const STATION_UNLOADER As String = "UNLOADER" * * * * Public Const ST_KEEP_ALIVE_START As String = "00" * Public Const ST_KEEP_ALIVE As String = "01" * * * Public Const ST_PRINTER_INIT As String = "02" * Public Const ST_PRINTER_WARM_START As String = "03" * Public Const ST_PRINTER_READY As String = "04" * Public Const ST_PRINTER_WAIT_SHEET_LOADED As String = "05" * Public Const ST_PRINTER_PRINTING As String = "06" * Public Const ST_PRINTER_WAIT_SHEET_UNLOADED As String = "07" * Public Const ST_PRINTER_WAIT_PROGRAM As String = "08" * * ------------------------------------------------------------------ */ bool answ = false; DataLayer DLMan = new DataLayer(); // recupero clockDrift string clockDriftKey = $"{redProdMachClock}:{updateRecords.Machine}"; string rawDrift = memLayer.ML.getRSV(clockDriftKey); double driftSec = 0; if (!string.IsNullOrEmpty(rawDrift)) { double.TryParse(rawDrift, out driftSec); } // salvo in mongo x debug ComLib.man.saveProdStat(updateRecords); // verifica preliminare della PLACE checkPlace(updateRecords.Machine); // salvo sul DB il set di dati... foreach (var item in updateRecords.Records) { // i keep alive NON li scrivo ma processo switch (item.Code) { case "00": // è PRIMO keepalive --> uso x sync dell'orologio DateTime adesso = DateTime.Now; DateTime machClock = item.DtRecord; driftSec = adesso.Subtract(machClock).TotalSeconds; // salvo memLayer.ML.setRSV(clockDriftKey, $"{driftSec}"); break; case "01": // savo status alive ComLib.setMachLiveStatus(updateRecords.Machine, true); break; default: break; } DLMan.taStatLog.insert(item.DtRecord.AddMilliseconds(driftSec), updateRecords.Machine, item.Station, item.Code, item.Payload, 0); } // chiamo procedura x fix durate DLMan.taStatLog.updateDuration(updateRecords.Machine); // recupero ultimo record ricevuto try { string station = ""; MachineStatRecord lastRecord = new MachineStatRecord(); station = "PRINTER"; lastRecord = updateRecords.Records.Where(x => x.Station == station).OrderByDescending(x => x.DtRecord).FirstOrDefault(); if (lastRecord != null) saveStatus(updateRecords.Machine, station, lastRecord); station = "NC_MACHINE"; lastRecord = updateRecords.Records.Where(x => x.Station == station).OrderByDescending(x => x.DtRecord).FirstOrDefault(); if (lastRecord != null) saveStatus(updateRecords.Machine, station, lastRecord); station = "UNLOADER"; lastRecord = updateRecords.Records.Where(x => x.Station == station).OrderByDescending(x => x.DtRecord).FirstOrDefault(); if (lastRecord != null) saveStatus(updateRecords.Machine, station, lastRecord); answ = true; } catch { } return answ; } /// /// Reset stati macchina registrati /// /// public static bool prodMachStateDataReset() { bool answ = memLayer.ML.setRSV(redProdMachStateData, "", 1); return answ; } /// /// Effettua divisione evitando zeri a den... /// /// /// /// public static double ratioProt(double num, double den) { den = den == 0 ? 1 : den; return num / den; } /// /// 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; } /// /// Reset della cache dei BatchDescendant x ID indicato /// /// public static void ResetBatchDescendant(int BatchId) { string redKey = $"{redBatchDescend}:{BatchId}"; memLayer.ML.setRSV(redKey, "", 10); } /// /// 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; } /// /// resetto curr bunk /// /// public static void resetCurrBunk(string machine = "WRK001") { // svuoto" memLayer.ML.redFlushKey(redCurrBunkTabKey(machine)); } /// /// resetto curr sheets /// /// public static void resetCurrSheet(string machine = "WRK001") { // svuoto sheet speciali memLayer.ML.redFlushKey(redCurrSheetTabKey(machine)); // svuoto tutti i fogli in cache x LOAD page memLayer.ML.redFlushKey(redCurrSheetTabKey(machine, -1, 0, 0)); } /// /// 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); } // salvo! rawData = JsonConvert.SerializeObject(dictData); memLayer.ML.setRSV($"{redKeyBase}:ItemsSel", rawData); answ = true; } catch { } } // reset memoria redis del CSS x obbligare refresh... memLayer.ML.setRSV($"{redKeyBase}:Css", ""); return answ; } /// /// Reset della cache dei BatchDescendant x ID indicato /// /// public static void ResetOrderByBatch(int BatchId) { string redKey = $"{redOrders}:BYBATCH:{BatchId}"; memLayer.ML.setRSV(redKey, "", 10); } /// /// Resetto i dati PRIMA di salvare i nuovi dati dal nesting /// /// /// public static void resetPrevDataFromNesting(int BatchID) { //elimino dati child MA NON il batch... DataLayer DLMan = new DataLayer(); DLMan.taBL.deleteTree(BatchID, 0); } /// /// Resetto in REDIS i dati di bunk (corrente e successivi) /// public static void resetRedisBunkData(string machine) { resetCurrBunk(); resetCurrSheet(); setCurrBatchId(machine, 0); setCurrBunkId(machine, 0); setCurrSheetId(machine, 0); redisFirstBunk = null; } /// /// Annulla (Svuota) richiesta di esecuzione di CAM /// /// public static bool resetRequestToNest() { bool answ = false; 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(); try { if (!string.IsNullOrEmpty(rawData)) { dictData = JsonConvert.DeserializeObject>(rawData); } // 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; } /// /// 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; } /// /// Invia una richiesta di esecuzione di Stima/Nesting x un Batch /// /// Batch di cui si chiede processing /// note opzionali /// Tipo processo: 1 = stima, 2 = nesting, 3 = stima EXTENDED /// /// Indica se sia validazione (part o disegno) --> in tal caso MaxTime = 1 /// /// Numero di indice richiesto con cui partire x creare CART/BIN /// /// Richiesta creazione png delle part valutate, da impiegare x DXF validation /// /// public static bool sendBatchReq(int BatchID, string note, int pType, bool isValidation, int numIndexStart, bool createPng) { string logIdKey = $"sendBatchReq | BatchID: {BatchID}"; // loggo richiesta Log.Instance.Info($"{logIdKey} | numIndexStart: {numIndexStart}"); Log.Instance.Info($"{logIdKey} | note: {note} | pType: {pType} | isValidation: {isValidation} | createPng: {createPng}"); DataLayer DLMan = new DataLayer(); 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 { // preliminare: se è stima EXT --> riporto pezzi su ordine ORIGINALE... if (pType == 3) { DLMan.taOLT.setBatchSplit(BatchID, false); } // in base allo stato del BATCH corrente determino il tempo e le opzioni da inviare... var batch = DLMan.taBL.getByKey(BatchID); int mTime = 1; // se non è validazione verifico che tempo impostare... if (!isValidation) { 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 = DLMan.taOL.getByBatch(BatchID); // leggo tab KIT da DB var tblKit = DLMan.taKL.getByBatch(BatchID); // leggo tab ITEMS da DB var tblItm = DLMan.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.FamilyCode, 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, NumIndexStart = numIndexStart, CreatePng = createPng }; // 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 currBatchReq = nextEnv; answ = true; } catch { } Log.Instance.Info($"{logIdKey} | req completed | currBatchReq: {nextEnv}"); // restituisco ok return answ; } /// /// Manda il primo batch di VALIDAZIONE al NESTING... /// /// indica se creare le PNG delle part validate /// public static bool sendFirstValidationBatch(bool createPng) { DataLayer DLMan = new DataLayer(); bool answ = false; // verifico se NON CI SIANO GIA' validazioni in corso... var tabBatchRunning = DLMan.taBL.getByStatus(1, "", true, 0); if (tabBatchRunning.Count == 0) { // ora verifico, se ci sono batch per FILE (dxf) VALIDATION in stato 8 (da validare) // --> metto in coda! DS_App.BatchListDataTable tabBatch = DLMan.taBL.getByStatus(8, "", true, 2); // se non ne ho cerco nei PartValidation if (tabBatch.Count == 0) { tabBatch = DLMan.taBL.getByStatus(8, "", true, 1); } if (tabBatch.Count > 0) { // 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, true, 1, createPng); // registro su DB nesting iniziato... QUANDO MI RISPONDE dovrò verificare // che era un batch x VALIDAZIONE DLMan.taBL.updateStatus(nextBatchId, (int)BatchStatus.EstimationRequested, "", 0); answ = true; } } } // resituisco return answ; } /// /// Salva su redis l'oggetto dei materiali serializzato /// /// public static bool sendMaterials() { bool answ = false; // leggo tab MATERIALS da DB DataLayer DLMan = new DataLayer(); var table = DLMan.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; } /// /// 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) { DataLayer DLMan = new DataLayer(); 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; // FIX pType a ESTIM int pType = 1; // ora ITEMS var tblItm = DLMan.taIL.getByOfflineOrder(OffOrderID); // 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(); // elenco ITEMS foreach (var rigaItem in tblItm) { 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 = OffOrderID, KitExtCode = $"OOK{OffOrderID:000000000}", PartList = listPart }; listKit.Add(currentKit); // compongo ordine currOrder = new Order() { OrderId = OffOrderID, OrderCod = $"OFOR{OffOrderID:000000000}", OrderExtCode = $"OFOR{OffOrderID:000000000}", DestPlant = "00", KitList = listKit }; listOrder.Add(currOrder); // ora versione gerarchica batchRequest newBatchreq = new batchRequest() { BatchId = -OffOrderID, EnvNum = nextEnv, MaxTime = mTime, ProcType = pType, MachineType = mType.Offline, OrderType = oType.OfflineOrder, 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 currBatchReq = nextEnv; answ = true; } catch (Exception exc) { Log.Instance.Error($"Eccezione in sendOfflineOrderReq:{Environment.NewLine}{exc}"); } // restituisco ok return answ; } /// /// Helper x serializzare l'oggetto /// /// /// public static string serializeTakt(Takt currData) { string answ = JsonConvert.SerializeObject(currData); return answ; } /// /// Salvataggio in redis del BunkID in lavorazione sulla macchina /// public static void setCurrBatchId(string macchina, int BatchID) { memLayer.ML.setRSV(redCurrBatchId(macchina), BatchID.ToString()); } /// /// Salvataggio in redis del BunkID in lavorazione sulla macchina /// public static void setCurrBunkId(string macchina, int BunkID) { memLayer.ML.setRSV(redCurrBunkId(macchina), BunkID.ToString()); } /// /// Salvataggio in redis del SheetID in lavorazione sulla macchina /// public static void setCurrSheetId(string macchina, int SheetID) { memLayer.ML.setRSV(redCurrSheetId(macchina), SheetID.ToString()); } public static bool setMachLiveStatus(string machine, bool isLive) { string redKey = $"{redProdMachStateLive}:{machine}"; string redVal = $"{isLive}"; // salvo x 90 sec bool done = memLayer.ML.setRSV(redKey, redVal, 90); return done; } /// /// Salva per 5 sec la richiesta di reload delle pagine MachineUnload /// public static void setReloadMU() { memLayer.ML.setRSV(redMachUnloadForce, "true", 5); } /// /// Salva su REDIS richiesta visualizzaizone SecondScreen x /// /// cod schermo, formato SSC000000 /// Path file richiesto (pdf) /// durata in redis della richiesta /// public static bool setSecScreenRequest(string secScreenCode, string filePath, int ttl_sec) { bool answ = false; // recupero ultima call string redKey = $"{redSecScreenReq}:{secScreenCode}"; answ = memLayer.ML.setRSV(redKey, filePath, ttl_sec); return answ; } /// /// Recupero dati sheet da Redis/DB /// public static DS_App.SheetListDataTable SheetTabGet(string Machine, int BatchId, int StMin, int StMax) { DS_App.SheetListDataTable answ = null; string redKey = redCurrSheetTabKey(Machine, BatchId, StMin, StMax); string rawData = memLayer.ML.getRSV(redKey); if (!string.IsNullOrEmpty(rawData)) { try { // deserializzo... answ = JsonConvert.DeserializeObject(rawData); } catch { } } else { // leggo DB DataLayer DLMan = new DataLayer(); answ = DLMan.taSHL.getByMLStatus(BatchId, StMin, StMax, Machine); rawData = JsonConvert.SerializeObject(answ); // salvo in cache x 30 sec memLayer.ML.setRSV(redKey, rawData, 30); } return answ; } /// /// Wrapper traduzione termini /// /// /// public static string traduci(string lemma) { return user_std.UtSn.Traduci(lemma); } /// /// Aggiorna la POSITION del BATCH a aprtire dallo stato DI TUTTI i bunk 0 = not started, 1 /// = STACKS started, 2 = STACKS done, 3 = Current, 4 = Completed /// /// /// public static void updateBatchPosition(int BatchID) { DataLayer DLMan = new DataLayer(); // chiamo stored x checkPosition DLMan.taBL.checkPosition(BatchID); } /// /// Aggiorna la POSITION del BATCH a partire dallo stato dei bunk/stack selezionato 0 = not /// started, 1 = STACKS started, 2 = STACKS done, 3 = Current, 4 = Completed /// /// /// public static void updateBatchPositionByBunk(int BunkID) { DataLayer DLMan = new DataLayer(); // recupero il BatchID DS_App.StackListDataTable tabBunk = DLMan.taSTL.getByKey(BunkID); if (tabBunk.Count > 0) { try { int BatchID = tabBunk[0].BatchID; // chiamo procedura di check sull'intero bunk updateBatchPosition(BatchID); } catch { } } } /// /// Salvo dati su PartList ricevuti da Nesting (COMPETATO) /// /// /// public static void updateBinsFromNesting(int BatchID, List BinList) { Dictionary part2update = new Dictionary(); DataLayer DLMan = new DataLayer(); // inizio a processare... bunks! if (BinList != null) { foreach (var item in BinList) { // creo il BIN! object newBin = DLMan.taBN.insertAndReturn(item.BinIndex); int BinID = 0; bool valOk = int.TryParse(newBin.ToString(), out BinID); // se ho un BIN in risposta... if (valOk) { // processo sheets if (item.PartList != null) { foreach (var part in item.PartList) { // creo lo sheet... var newB2I = DLMan.taBNLS.insertAndReturn(BinID, part.PartId); } } } // verifico se aggiornare part if (!part2update.ContainsKey(item.PartRev)) { part2update.Add(item.PartRev, item.PartExtCode); } } // verifico se ho part da aggiornare if (part2update.Count > 0) { // recupero tabella parts in blocco da batch var item4batch = DLMan.taIL.getByBatch(BatchID); // chiamo stored x ogni esempio di part foreach (var item in part2update) { var currItemList = item4batch.Where(x => x.ItemExtCode == item.Value).ToList(); if (currItemList != null && currItemList.Count > 0) { // processo! foreach (var currPart in currItemList) { DLMan.taIL.updateExtCodeFromBinNesting(BatchID, item.Value, item.Key); } } } } } } /// /// Salvo dati Bunks/Sheets/Parts ricevuti da Nesting (COMPETATO) /// /// /// public static void updateBunksFromNesting(int BatchID, List BunkList) { DataLayer DLMan = new DataLayer(); // inizio a processare... bunks! if (BunkList != null) { foreach (var bunk in BunkList) { // creo il BUNK! var newBunk = DLMan.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 = DLMan.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) DLMan.taNest.insertAndReturn(currSheet.SheetID, part.PartId); } } // ora salvo ANCHE i remnants dello sheet... SE ci sono if (sheet.Remnant != null) { DLMan.taRem.insertAndReturn(BatchID, sheet.MatId, currSheet.SheetID, sheet.Remnant.L_mm, sheet.Remnant.W_mm, false); } } } } } } } } /// /// Salvo dati su PartList ricevuti da Nesting (COMPETATO) /// /// /// public static void updateCartsFromNesting(int BatchID, List CartList) { Dictionary part2update = new Dictionary(); DataLayer DLMan = new DataLayer(); // inizio a processare... bunks! if (CartList != null) { foreach (var item in CartList) { // creo il CART! var newCart = DLMan.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 = DLMan.taKL.updateCart(kit.KitId, currCart.CartID); // verifico x update PartExtCode addPart2Upd(ref part2update, kit.PartList); } } } } } // verifico se ho part da aggiornare if (part2update.Count > 0) { // recupero tabella parts in blocco da batch var item4batch = DLMan.taIL.getByBatch(BatchID); // chiamo stored x ogni esempio di part foreach (var item in part2update) { var currItem = item4batch.Where(x => x.ItemID == item.Value).FirstOrDefault(); // verifico SE sia da processare... if (currItem != null && currItem.ItemExtCode != item.Key) { DLMan.taIL.updateExtCodeFromNesting(BatchID, item.Value, item.Key); } } } } /// /// 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; } /// /// Salvo dati di OrderId ricevuti da Nesting (stima) /// /// public static void updateExtEstimFromNesting(int BatchId, List OrdExtList) { DataLayer DLMan = new DataLayer(); // svuoto x batch... DLMan.taOLT.deleteByBatch(BatchId); // salvo elenco materiali x ogni item... foreach (var currItem in OrdExtList) { // tempo in sec --> divido 60 DLMan.taOLT.insert(BatchId, BatchId, currItem.OrderId, currItem.OrderExtCode, currItem.NumBin, currItem.NumCart, currItem.NumPart, (currItem.TotTime / 60)); } } /// /// Salvo dati su PartList ricevuti da Nesting (stima) /// /// public static void updatePartsFromNesting(List PartList) { DataLayer DLMan = new DataLayer(); 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); DLMan.taIL.updateFromNesting(currItem.PartId, currItem.MatId, PostProcList, ProcessesReq, pdfFilePath); } } /// /// Fornisce un dictionary di valori ATTUALI per una specifica macchina /// /// /// public Dictionary getCurrMachineData(string machineCod) { Dictionary answ = new Dictionary(); // cerco in REDIS string rawData = memLayer.ML.getRSV(machineArea(machineCod)); if (!string.IsNullOrEmpty(rawData)) { answ = JsonConvert.DeserializeObject>(rawData); } else { // recupero batch e sheet... int batchId = getNextBatch(machineCod); // se non trovo creo un oggetto NUOVO e vuoto x ogni oggetto... e salvo... answ.Add("BatchID", batchId.ToString()); answ.Add("SheetID_load", getSheetIdByBatch(batchId, 0, 1, machineCod).ToString()); answ.Add("SheetID_print", getSheetIdByBatch(batchId, 1, 2, machineCod).ToString()); answ.Add("SheetID_work", getSheetIdByBatch(batchId, 2, 3, machineCod).ToString()); answ.Add("SheetID_unload", getSheetIdByBatch(batchId, 3, 5, machineCod).ToString()); // serializzo e salvo! saveMachineData(machineCod, answ); } // restituisco! 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 stima ESTESA salvata /// /// /// public nestReplyBatchExtEst getExtEstAnsw(int BatchID) { nestReplyBatchExtEst answ = null; try { // definisco filtro var filtBuilder = Builders.Filter; var filter = filtBuilder.Eq("BatchID", BatchID); var collRawData = database.GetCollection("ExtendedEstimationArchive"); // 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; } /// /// Elimina da tutti archivi MongoDB i dati relativi ad un dato EnvNum /// /// Stringa EnvNum da eliminare /// public bool MongoDeleteEnvData(string EnvNum) { bool answ = false; bool okEstArch = MongoEstArchDeleteEnvData(EnvNum); bool okExtEstArch = MongoExtEstArchDeleteEnvData(EnvNum); bool okNestArch = MongoNestArchDeleteEnvData(EnvNum); bool okOfflArch = MongoOffArchDeleteEnvData(EnvNum); answ = okEstArch || okExtEstArch || okNestArch || okOfflArch; return answ; } /// /// Elimina da EstimationArchive MongoDB i dati relativi ad un dato EnvNum /// /// Stringa EnvNum da eliminare /// public bool MongoEstArchDeleteEnvData(string EnvNum) { bool answ = false; try { // definisco filtro var filtBuilder = Builders.Filter; var filter = filtBuilder.Eq("EnvNum", EnvNum); var collRawData = database.GetCollection("EstimationArchive"); // elimino old collRawData.DeleteMany(filter); answ = true; } catch { } return answ; } /// /// Elimina da EstimationArchive MongoDB i dati relativi ad un dato EnvNum /// /// Stringa EnvNum da eliminare /// public bool MongoExtEstArchDeleteEnvData(string EnvNum) { bool answ = false; try { // definisco filtro var filtBuilder = Builders.Filter; var filter = filtBuilder.Eq("EnvNum", EnvNum); var collRawData = database.GetCollection("ExtendedEstimationArchive"); // elimino old collRawData.DeleteMany(filter); answ = true; } catch { } return answ; } /// /// Elimina da EstimationArchive MongoDB i dati relativi ad un dato EnvNum /// /// Stringa EnvNum da eliminare /// public bool MongoNestArchDeleteEnvData(string EnvNum) { bool answ = false; try { // definisco filtro var filtBuilder = Builders.Filter; var filter = filtBuilder.Eq("EnvNum", EnvNum); var collRawData = database.GetCollection("NestingArchive"); // elimino old collRawData.DeleteMany(filter); answ = true; } catch { } return answ; } /// /// Elimina da EstimationArchive MongoDB i dati relativi ad un dato EnvNum /// /// Stringa EnvNum da eliminare /// public bool MongoOffArchDeleteEnvData(string EnvNum) { bool answ = false; try { // definisco filtro var filtBuilder = Builders.Filter; var filter = filtBuilder.Eq("EnvNum", EnvNum); var collRawData = database.GetCollection("OfflineArchive"); // elimino old collRawData.DeleteMany(filter); answ = true; } catch { } return answ; } /// /// 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; } /// /// 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; } /// /// 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 STIMA ESTESA /// /// Stringa della risposta JSON ricevuta dal nesting /// public bool saveExtEstAnsw(nestReplyBatchExtEst nestAnsw) { bool answ = false; try { // definisco filtro var filtBuilder = Builders.Filter; var filter = filtBuilder.Eq("BatchID", nestAnsw.BatchID); var collRawData = database.GetCollection("ExtendedEstimationArchive"); // elimino old collRawData.DeleteMany(filter); // aggiungo collRawData.InsertOne(nestAnsw); answ = true; } catch { } return answ; } /// /// Salvataggio array dati di una macchina /// /// /// /// public bool saveMachineData(string machineCod, Dictionary paramsArray) { bool answ = false; try { // serializzo e salvo! string rawData = JsonConvert.SerializeObject(paramsArray); memLayer.ML.setRSV(machineArea(machineCod), rawData); answ = true; } catch { } // restituisco! return answ; } /// /// Fornisce un dictionary di valori ATTUALI per una specifica macchina /// /// /// /// /// public bool saveMachineParam(string machineCod, string Key, string Val) { bool answ = false; // recupero i dati try { var currData = getCurrMachineData(machineCod); // aggiorno il record if (currData.ContainsKey(Key)) { currData[Key] = Val; } // oppure aggiungo... else { currData.Add(Key, Val); } // salvo... saveMachineData(machineCod, currData); 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; } /// /// Salva una risposta ricevuta x OfflineOrder /// /// Stringa della risposta JSON ricevuta dal nesting /// public bool saveOffOrdAnsw(nestReplyOffOrd offOrdAnsw) { bool answ = false; try { // definisco filtro var filtBuilder = Builders.Filter; var filter = filtBuilder.Eq("BatchID", offOrdAnsw.BatchID); var collRawData = database.GetCollection("OfflineArchive"); // elimino old collRawData.DeleteMany(filter); // aggiungo collRawData.InsertOne(offOrdAnsw); answ = true; } catch { } return answ; } /// /// Salva una risposta ricevuta dal PROD /// /// Stringa della risposta JSON ricevuta dal PROD /// public bool saveProdAnsw(SheetWorkList prodAnsw) { bool answ = false; try { // definisco filtro var filtBuilder = Builders.Filter; // filtro vuoto x svuotare sempre var filter = filtBuilder.Empty; var collRawData = database.GetCollection("ProdArchive"); // elimino old (TUTTI!!!) collRawData.DeleteMany(filter); // aggiungo collRawData.InsertOne(prodAnsw); // fatto! answ = true; } catch { } return answ; } /// /// Salva una risposta ricevuta x OfflineOrder /// /// Stringa della risposta JSON ricevuta dal nesting /// public bool saveProdStat(MachineStatData offOrdAnsw) { bool answ = false; try { // definisco filtro var filtBuilder = Builders.Filter; #if false //var filter = filtBuilder.Eq("BatchID", offOrdAnsw.BatchID); #endif var collRawData = database.GetCollection("ProdStat"); // elimino old #if false //collRawData.DeleteMany(filter); #endif // aggiungo collRawData.InsertOne(offOrdAnsw); answ = true; } catch { } return answ; } /// /// Effettua il ricalcolo delle statistiche x SheetStat --> BatchStat dato un BatchID /// recuperando i dati da MongoDB /// /// /// public bool updateSheetStatsByBatch(int BatchID) { bool answ = false; DataLayer DLMan = new DataLayer(); List PaintPartList = new List(); // cerco da lista salvataggi Estim/Nest... var nestAnsw = getNestAnsw(BatchID); if (nestAnsw != null) { // inizio eliminando le vecchie statistiche x foglio DLMan.taShStats.resetBatch(BatchID); // recupero i pitturati try { if (nestAnsw.BinList != null) { foreach (var bin in nestAnsw.BinList) { // se ho parti le aggiungo if (bin.PartList != null) { foreach (var Part in bin.PartList) { PaintPartList.Add(Part.PartId); } } } } } catch { } // il tot delle part è in bunk > Sheet > part try { if (nestAnsw.BunkList != null) { int sheetIdx = 0; foreach (var bunk in nestAnsw.BunkList) { foreach (var sheet in bunk.SheetList) { // incremento contatore sheets sheetIdx++; // dati resa superfici double num = sheet.SurfaceWork > 0 ? sheet.SurfaceWork : 0; double den = sheet.SurfaceTotal > 0 ? sheet.SurfaceTotal : 1; // parts del foglio List PartList = sheet.PartList.Select(x => x.PartId).ToList(); int numPaint = PartList.Intersect(PaintPartList).Count(); // qui salvo le statistiche DLMan.taShStats.upsertQuery(BatchID, sheetIdx, sheet.MatId, (decimal)num, (decimal)den, sheet.PartList.Count, numPaint); //DLMan.taShStats.upsertQuery(BatchID, sheet.SheetIndex, sheet.MatId, (decimal)num, (decimal)den, sheet.PartList.Count, numPaint); } } } } catch { } // finisco calcolando le statistiche x Batch... DLMan.taBStats.refresh(BatchID); } return answ; } #endregion Public Methods #region Public Classes public class Parte { #region Public Properties public string CadFilePath { get; set; } public string DataMatrix { get; set; } public string Description { get; set; } public string ExtCode { get; set; } public int MatId { get; set; } public int PartId { get; set; } public string PostProc { get; set; } public string ProcessReq { get; set; } public int Qty { get; set; } #endregion Public Properties } /// /// Oggetto globale TAKT /// public class Takt { #region Public Properties /// /// Numero di Stack da lavorare /// public int NumStack { get { int answ = 0; try { answ = StackList.Count; } catch { } return answ; } } /// /// Elenco degli Stack da lavorare /// public List StackList { get; set; } /// /// Stato del TAKT /// public CStatus Status { get; set; } /// /// Codice univoco oggetto TAKT (data.num) /// public string TaktId { get; set; } #endregion Public Properties } #endregion Public Classes #region Protected Fields /// /// Chiave primo bunk su redis /// protected static string redAllNextBunkKey = $"{redProdReq}:NextBunk"; /// /// Chiave primo bunk su redis /// protected static string redFirstBunkKey = $"{redProdReq}:FirstBunk"; /// /// TTL standard x dati da scambiare con PROD (30 gg) /// protected static int ttlProdData = 3600 * 24 * 30; #endregion Protected Fields #region Protected Methods /// /// lettura currBunk table da cache /// /// /// protected static DS_App.StackListDataTable getCurrBunkTab(string machine) { DS_App.StackListDataTable answ = null; string rawData = memLayer.ML.getRSV(redCurrBunkTabKey(machine)); if (!string.IsNullOrEmpty(rawData)) { try { // deserializzo... answ = JsonConvert.DeserializeObject(rawData); } catch { } } return answ; } /// /// Recupero da redis tab fogli correnti (5:5) /// protected static DS_App.SheetListDataTable getCurrSheetTab(string machine) { DS_App.SheetListDataTable answ = null; string rawData = memLayer.ML.getRSV(redCurrSheetTabKey(machine)); if (!string.IsNullOrEmpty(rawData)) { try { // deserializzo... answ = JsonConvert.DeserializeObject(rawData); } catch { } } return answ; } /// /// Chiave BATCH corrente su redis /// /// /// protected static string redCurrBatchId(string machine) { string answ = ""; if (string.IsNullOrEmpty(machine)) { answ = $"{redProdReq}:CurrBatchID"; } else { answ = $"{redProdReq}:CurrBatchID:{machine}"; } return answ; } /// /// Chiave Bunk corrente su redis /// /// /// protected static string redCurrBunkId(string machine) { string answ = ""; if (string.IsNullOrEmpty(machine)) { answ = $"{redProdReq}:CurrBunkID"; } else { answ = $"{redProdReq}:CurrBunkID:{machine}"; } return answ; } /// /// Chiave bunk corrente su redis /// /// /// protected static string redCurrBunkTabKey(string machine) { string answ = ""; if (string.IsNullOrEmpty(machine)) { answ = $"{redProdReq}:CurrBunks"; } else { answ = $"{redProdReq}:CurrBunks:{machine}"; } return answ; } /// /// Chiave Sheets corrente su redis /// /// /// protected static string redCurrSheetId(string machine) { string answ = ""; if (string.IsNullOrEmpty(machine)) { answ = $"{redProdReq}:CurrSheetID"; } else { answ = $"{redProdReq}:CurrSheetID:{machine}"; } return answ; } /// /// Chiave sheets correnti su redis /// /// /// protected static string redCurrSheetTabKey(string machine) { string answ = ""; if (string.IsNullOrEmpty(machine)) { answ = $"{redProdReq}:CurrSheets"; } else { answ = $"{redProdReq}:CurrSheets:{machine}"; } return answ; } /// Chiave sheets correnti su redis /// BatchId, se fosse <= 0 --> chiave parent utile x reset /// protected static string redCurrSheetTabKey(string Machine, int BatchId, int StMin, int StMax) { string answ = ""; if (BatchId > 0) { answ = $"{redProdReq}:SheetByMBS:{Machine}:{BatchId}:{StMin}:{StMax}"; } else { answ = $"{redProdReq}:SheetByMBS:{Machine}"; } return answ; } /// /// Chiave primo bunk su redis /// protected static string redNextBunkKey(int BunkID) { return $"{redProdReq}:NextBunk:{BunkID}"; } /// /// salvataggio inc ache currBunk table /// /// /// protected static void setCurrBunkTab(string machine, DS_App.StackListDataTable tabBunks) { string rawData = JsonConvert.SerializeObject(tabBunks); // TTL 15 sec memLayer.ML.setRSV(redCurrBunkTabKey(machine), rawData, 15); } /// /// Salvataggio in redis tab fogli correnti /// /// /// protected static void setCurrSheetTab(string machine, DS_App.SheetListDataTable tabella) { string rawData = JsonConvert.SerializeObject(tabella); // TTL 1 sec memLayer.ML.setRSV(redCurrSheetTabKey(machine), rawData, 1); } /// /// Recupera prossimo batch da DB (NEXT... da db x status...) /// protected int getNextBatch(string PlaceCod) { DataLayer DLMan = new DataLayer(); int answ = 0; try { var currData = DLMan.taBL.getNextAvailable(PlaceCod); if (currData.Count > 0) { answ = currData[0].BatchID; } } catch { } return answ; } /// /// Recupera PRIMO SHEET da batch e stati permessi... /// /// /// /// /// /// protected int getSheetIdByBatch(int BatchID, int minVal, int maxVal, string machine) { int answ = 0; if (BatchID > 0 && !string.IsNullOrEmpty(machine)) { try { // 2023.10.27 passaggio versione cached #if false DataLayer DLMan = new DataLayer(); var tabSheet = DLMan.taSHL.getByMLStatus(BatchID, minVal, maxVal, machine); #endif var tabSheet = SheetTabGet(machine, BatchID, minVal, maxVal); if (tabSheet.Count > 0) { answ = tabSheet[0].SheetID; } } catch { } } return answ; } #endregion Protected Methods #region Private Fields /// /// Database corrente MongoDB /// private IMongoDatabase database; #endregion Private Fields #region Private Properties /// /// Cache redis del PRIMO bunk da lavorare /// private static ProdBunk redisFirstBunk { get { ProdBunk answ = null; string rawData = memLayer.ML.getRSV(redFirstBunkKey); if (!string.IsNullOrEmpty(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); // imposto force reload UNLOAD setReloadMU(); } } } #endregion Private Properties #region Private Methods /// /// Verifica ed eventualmente aggiunge part da aggiornare all'elenco /// /// /// private static void addPart2Upd(ref Dictionary part2update, List partList) { foreach (var item in partList) { if (!part2update.ContainsKey(item.PartRev)) { part2update.Add(item.PartRev, item.PartId); } } } /// /// verifica che la macchina dichiarata esiste o la crea... /// /// private static void checkPlace(string machine) { DS_App.PlacesDataTable tabPlace = new DS_App.PlacesDataTable(); DataLayer DLMan = new DataLayer(); // cerco in Redis... string rawData = memLayer.ML.getRSV(redProdMachList); // provo a deserializzare e cercare... if (!string.IsNullOrEmpty(rawData)) { tabPlace = JsonConvert.DeserializeObject(rawData); } // cerco item var foundItem = tabPlace.Where(x => x.PlaceCod == machine).ToList(); if (foundItem.Count == 0) { // forzo (ri)lettura... tabPlace = DLMan.taPlac.GetData(); rawData = JsonConvert.SerializeObject(tabPlace); memLayer.ML.setRSV(redProdMachList, rawData); } // cerco di nuovoitem foundItem = tabPlace.Where(x => x.PlaceCod == machine).ToList(); if (foundItem.Count == 0) { // se non ci fosse --> creo DLMan.taPlac.insert(machine); // inserisco empty x 1 sec così rileggerà... memLayer.ML.setRSV(redProdMachList, "", 1); } } /// /// Transcodifica dati da format DB a formato PROD /// /// Elenco fogli da DB /// private static SheetWorkList convertSheetWorkList(List sheetList) { SheetWorkList answ; List elSheet = new List(); string nestBasePath = memLayer.ML.CRS("nestBasePath").ToLower(); string servBasePath = memLayer.ML.CRS("servBasePath").ToLower(); string prodBasePath = memLayer.ML.CRS("prodBasePath").ToLower(); DateTime dataStart = DateTime.Now; ProdSheetExt currPanel; // ciclo elenco fogli x escludere lavorati... foreach (var item in sheetList) { // 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.ToLower().Replace(nestBasePath, prodBasePath).Replace(servBasePath, prodBasePath) }; WorkData wdMachining = new WorkData() { DtStart = item.IsWrkStartNull() ? null : (DateTime?)item.WrkStart, DtEnd = item.IsWrkEndNull() ? null : (DateTime?)item.WrkEnd, ProgramPath = item.CncFilePath.ToLower().Replace(nestBasePath, prodBasePath).Replace(servBasePath, prodBasePath) }; 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 ProdSheetExt() { BunkId = item.StackID, Printing = wdPrint, Machining = wdMachining, Material = material, SheetId = item.SheetID, SheetIndex = item.SheetIndex, Status = currPnlStatus, Unloading = wdUnload }; elSheet.Add(currPanel); if (!item.IsPrntStartNull()) { dataStart = item.PrntStart < dataStart ? item.PrntStart : dataStart; } } // compongo il bunk... answ = new SheetWorkList() { SheetList = elSheet }; return answ; } /// /// Recupera e transcodifica DA DB i dati di UN SINGOLO bunk /// /// /// private static ProdBunk getBunkFromDb(DS_App.StackListRow currBunk, string machine) { DataLayer DLMan = new DataLayer(); 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 = DLMan.taSHL.getByStack(currBunk.StackID, machine); DateTime dataStart = DateTime.Now; ProdSheet currPanel; string nestBasePath = memLayer.ML.CRS("nestBasePath").ToLower(); string servBasePath = memLayer.ML.CRS("servBasePath").ToLower(); string prodBasePath = memLayer.ML.CRS("prodBasePath").ToLower(); 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.ToLower().Replace(nestBasePath, prodBasePath).Replace(servBasePath, prodBasePath) }; WorkData wdMachining = new WorkData() { DtStart = item.IsWrkStartNull() ? null : (DateTime?)item.WrkStart, DtEnd = item.IsWrkEndNull() ? null : (DateTime?)item.WrkEnd, ProgramPath = item.CncFilePath.ToLower().Replace(nestBasePath, prodBasePath).Replace(servBasePath, prodBasePath) }; 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; } /// /// 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; } /// /// Aggiorno il record della station x la machine indicata /// /// /// /// /// private static MachineStatData saveStatus(string machine, string station, MachineStatRecord lastRecord) { MachineStatData currData = new MachineStatData() { Machine = machine }; string redKey = $"{redProdMachStateData}:{machine}"; // ora processo lo status attuale x salvare MAPPA ULTIMO status in Redis... string redVal = memLayer.ML.getRSV(redKey); if (!string.IsNullOrEmpty(redVal)) { currData = JsonConvert.DeserializeObject(redVal); } // recupero ultimo stato x la station corrente var stationRecord = currData.Records.Where(x => x.Station == station).FirstOrDefault(); if (stationRecord != null) { // lo rimuovo currData.Records.Remove(stationRecord); stationRecord = lastRecord; } // aggiungo... currData.Records.Add(lastRecord); // serializzo string rawData = JsonConvert.SerializeObject(currData); // salvo! memLayer.ML.setRSV(redKey, rawData); return currData; } /// /// 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), ""); } } #endregion Private Methods } }