Files
NKC/AppData/ComLib.cs
T
2020-08-19 13:06:41 +02:00

2568 lines
94 KiB
C#

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
{
/// <summary>
/// Classe con metodi di supporto per COMUNICAZIONE
/// </summary>
public class ComLib
{
#region Gestione persistenza risposte via REST da NESTING
/// <summary>
/// Database corrente MongoDB
/// </summary>
IMongoDatabase database;
/// <summary>
/// Init classe ComLib
/// </summary>
public ComLib()
{
database = memLayer.ML.getMongoDatabase("NKC");
}
/// <summary>
/// Classe impiego sstatico ComLib...
/// </summary>
public static ComLib man = new ComLib();
/// <summary>
/// Salva una risposta ricevuta x STIMA
/// </summary>
/// <param name="nestAnsw">Stringa della risposta JSON ricevuta dal nesting</param>
/// <returns></returns>
public bool saveEstAnsw(nestReplyBatchInitial nestAnsw)
{
bool answ = false;
try
{
// definisco filtro
var filtBuilder = Builders<nestReplyBatchInitial>.Filter;
var filter = filtBuilder.Eq<int>("BatchID", nestAnsw.BatchID);
var collRawData = database.GetCollection<nestReplyBatchInitial>("EstimationArchive");
// elimino old
collRawData.DeleteMany(filter);
// aggiungo
collRawData.InsertOne(nestAnsw);
answ = true;
}
catch
{ }
return answ;
}
/// <summary>
/// Salva una risposta ricevuta x NESTING
/// </summary>
/// <param name="nestAnsw">Stringa della risposta JSON ricevuta dal nesting</param>
/// <returns></returns>
public bool saveNestAnsw(nestReplyBatchFinal nestAnsw)
{
bool answ = false;
try
{
// definisco filtro
var filtBuilder = Builders<nestReplyBatchFinal>.Filter;
var filter = filtBuilder.Eq<int>("BatchID", nestAnsw.BatchID);
var collRawData = database.GetCollection<nestReplyBatchFinal>("NestingArchive");
// elimino old
collRawData.DeleteMany(filter);
// aggiungo
collRawData.InsertOne(nestAnsw);
answ = true;
}
catch
{ }
return answ;
}
/// <summary>
/// Salva una risposta ricevuta x OfflineOrder
/// </summary>
/// <param name="offOrdAnsw">Stringa della risposta JSON ricevuta dal nesting</param>
/// <returns></returns>
public bool saveOffOrdAnsw(nestReplyOffOrd offOrdAnsw)
{
bool answ = false;
try
{
// definisco filtro
var filtBuilder = Builders<nestReplyOffOrd>.Filter;
var filter = filtBuilder.Eq<int>("BatchID", offOrdAnsw.BatchID);
var collRawData = database.GetCollection<nestReplyOffOrd>("OfflineArchive");
// elimino old
collRawData.DeleteMany(filter);
// aggiungo
collRawData.InsertOne(offOrdAnsw);
answ = true;
}
catch
{ }
return answ;
}
/// <summary>
/// Recupero risposta stima salvata
/// </summary>
/// <param name="BatchID"></param>
/// <returns></returns>
public nestReplyBatchInitial getEstAnsw(int BatchID)
{
nestReplyBatchInitial answ = null;
try
{
// definisco filtro
var filtBuilder = Builders<nestReplyBatchInitial>.Filter;
var filter = filtBuilder.Eq<int>("BatchID", BatchID);
var collRawData = database.GetCollection<nestReplyBatchInitial>("EstimationArchive");
// recupero
answ = collRawData.Find(filter).Project<nestReplyBatchInitial>("{_id: 0}").FirstOrDefault<nestReplyBatchInitial>();
}
catch
{ }
return answ;
}
/// <summary>
/// Recupero risposta nesting salvata
/// </summary>
/// <param name="BatchID"></param>
/// <returns></returns>
public nestReplyBatchFinal getNestAnsw(int BatchID)
{
nestReplyBatchFinal answ = null;
try
{
// definisco filtro
var filtBuilder = Builders<nestReplyBatchFinal>.Filter;
var filter = filtBuilder.Eq<int>("BatchID", BatchID);
FindOptions opz = new FindOptions { ShowRecordId = false };
var collRawData = database.GetCollection<nestReplyBatchFinal>("NestingArchive");
// recupero
answ = collRawData.Find(filter).Project<nestReplyBatchFinal>("{_id: 0}").FirstOrDefault<nestReplyBatchFinal>();
}
catch
{ }
return answ;
}
/// <summary>
/// restitusice ultima chiamata REST registrata su REDIS
/// </summary>
/// <returns></returns>
public static string lastRestAnsw()
{
string answ = "";
// recupero ultima call
string redKey = $"{redNestAnsw}:LAST_CALL";
answ = memLayer.ML.getRSV(redKey);
return answ;
}
/// <summary>
/// Salva una risposta ricevuta dal PROD
/// </summary>
/// <param name="prodAnsw">Stringa della risposta JSON ricevuta dal PROD</param>
/// <returns></returns>
public bool saveProdAnsw(SheetWorkList prodAnsw)
{
bool answ = false;
try
{
// definisco filtro
var filtBuilder = Builders<SheetWorkList>.Filter;
// filtro vuoto x svuotare sempre
var filter = filtBuilder.Empty;
var collRawData = database.GetCollection<SheetWorkList>("ProdArchive");
// elimino old (TUTTI!!!)
collRawData.DeleteMany(filter);
// aggiungo
collRawData.InsertOne(prodAnsw);
// fatto!
answ = true;
}
catch
{ }
return answ;
}
#endregion
/// <summary>
/// Wrapper traduzione termini
/// </summary>
/// <param name="lemma"></param>
/// <returns></returns>
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 redMLCurrBunk = "NKC:SERV:TAKT:CurrBunk";
public static string redNestAnsw = "NKC:NEST:BANSW";
public static string redProdReq = "NKC:SERV:BUNKS";
public static string redProdAnsw = "NKC:PROD:BUNKS";
public static string redSecScreenReq = "NKC:SECSCREEN:REQ";
public static string redMachUnloadCount = "NKC:SERV:MACH_UNLOAD:COUNT";
public static string redMachUnloadForce = "NKC:SERV:MACH_UNLOAD:FORCERELOAD";
/// <summary>
/// chaive redis x cache conteggio coda PJQ
/// </summary>
public static string redQueueCount = "NKC:SERV:PJQ";
/// <summary>
/// chaive redis x cache conteggio coda PJQ composta da tante code
/// </summary>
public static string redQueueCountSet = "NKC:SERV:PJQCOUNT";
#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;
case BatchPosition.Current:
answ = traduci("BatchCurrent");
break;
case BatchPosition.Completed:
answ = traduci("BatchCompleted");
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 = 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;
default:
answ = traduci("NestStateUnk");
break;
}
}
catch
{ }
return answ;
}
/// <summary>
/// Oggetto globale TAKT
/// </summary>
public class Takt
{
/// <summary>
/// Codice univoco oggetto TAKT (data.num)
/// </summary>
public string TaktId { get; set; }
/// <summary>
/// Stato del TAKT
/// </summary>
public CStatus Status { get; set; }
/// <summary>
/// Elenco degli Stack da lavorare
/// </summary>
public List<ProdBunk> StackList { get; set; }
/// <summary>
/// Numero di Stack da lavorare
/// </summary>
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; }
}
/// <summary>
/// Salva su redis l'oggetto dei materiali serializzato
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// Restituisce il prossimo codice di envelope per comunicare con sistemi esterni
/// </summary>
/// <param name="BatchID">Batch contenuto nell'envelope</param>
/// <param name="note">note opzionali (motivo envelope)</param>
/// <returns></returns>
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<string, string> lista = new Dictionary<string, string>();
lista.Add(answ, $"{BatchID}|{note}");
memLayer.ML.redSaveHashDict(redMsgList, lista);
// ritorno
return answ;
}
/// <summary>
/// Restituisce elenco KVP delle buste ancora "pending" (quando processate le elimina da elenco...)
/// </summary>
/// <returns></returns>
public static KeyValuePair<string, string>[] getEnvList()
{
KeyValuePair<string, string>[] answ = memLayer.ML.redGetHash(redMsgList);
return answ;
}
/// <summary>
/// resetta la richeista corrente in modo che non ce ne siano altre in coda
/// </summary>
/// <returns></returns>
public static bool resetBatchReq()
{
bool answ = false;
try
{
currBatchReq = "";
answ = true;
}
catch
{ }
return answ;
}
public static string currBatchReqKey
{
get
{
return $"{redOutPath}:CURR";
}
}
/// <summary>
/// Valore della richiesta corrente di elaborazione batch
/// </summary>
public static string currBatchReq
{
get
{
return memLayer.ML.getRSV(currBatchReqKey);
}
set
{
// scrivo su REDIS
memLayer.ML.setRSV(currBatchReqKey, value);
}
}
/// <summary>
/// Manda il primo batch di VALIDAZIONE al NESTING...
/// </summary>
/// <returns></returns>
public static bool sendFirstValidationBatch()
{
bool answ = false;
// verifico se NON CI SIANO GIA' validazioni in corso...
var tabBatchRunning = DataLayer.man.taBL.getByStatus(1, "", 0);
if (tabBatchRunning.Count == 0)
{
// 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 batch x VALIDAZIONE
DataLayer.man.taBL.updateStatus(nextBatchId, (int)BatchStatus.EstimationRequested, "", 0);
answ = true;
}
}
}
// resituisco
return answ;
}
/// <summary>
/// Invia una richiesta di esecuzione di Nesting x un Batch
/// </summary>
/// <param name="BatchID">Batch di cui si chiede processing</param>
/// <param name="note">note opzionali</param>
/// <param name="pType">Tipo processo: 1 = stima, 2 = nesting</param>
/// <returns></returns>
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<Order> listOrder = new List<Order>();
List<Kit> listKit = new List<Kit>();
List<Part> listPart = new List<Part>();
// 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<Kit>();
// compongo kit
var righeKit = (DS_App.KitListRow[])tblKit.Select($"OrdID = {rigaOrd.OrdID}");
foreach (var rigaKit in righeKit)
{
listPart = new List<Part>();
// 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
};
// 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
{ }
// restituisco ok
return answ;
}
public static string canStartNewKey
{
get
{
return $"{redOutPath}:CanStartNew";
}
}
/// <summary>
/// verifica se sia avviabile un nuovo task nesting controllando cache Redis o tabelle batch/offlineOrders
/// </summary>
public static bool canStartNew
{
get
{
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 = DataLayer.man.taBL.getByStatus((int)BatchStatus.EstimationRequested, "", 0).Count;
int numNest = DataLayer.man.taBL.getByStatus((int)BatchStatus.NestRequested, "", 0).Count;
// ora controllo anche offline orders...
int numOffOrd = DataLayer.man.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;
}
}
/// <summary>
/// Verifica lo stato di una richiesta di esecuzione BATCH x stima/nesting
/// </summary>
/// <param name="OffOrderID">OfflineOrder di cui si chiede processing</param>
/// <param name="note">note opzionali</param>
/// <returns></returns>
public static bool checkBatchReq(int OffOrderID)
{
bool answ = false;
#if false
string typeSearch = "OffOrdCalculation";
string keyEnv = "";
// recupero lista dei vari task APERTI...
KeyValuePair<string, string>[] 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;
}
/// <summary>
/// Annulla (Svuota) richiesta di esecuzione di CAM
/// </summary>
/// <returns></returns>
public static bool resetRequestToNest()
{
bool answ = false;
return answ;
}
/// <summary>
/// Invia una richiesta di esecuzione di CAM x un ordine offline
/// </summary>
/// <param name="OffOrderID">OfflineOrder di cui si chiede processing</param>
/// <param name="note">note opzionali</param>
/// <returns></returns>
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;
// FIX pType a ESTIM
int pType = 1;
// ora ITEMS
var tblItm = DataLayer.man.taIL.getByOfflineOrder(OffOrderID);
// init oggetti x fare cicli...
Order currOrder = null;
Kit currentKit = null;
Part currPart = null;
List<Order> listOrder = new List<Order>();
List<Kit> listKit = new List<Kit>();
List<Part> listPart = new List<Part>();
// 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
memLayer.ML.setRSV(currBatchReqKey, nextEnv);
answ = true;
}
catch (Exception exc)
{
logger.lg.scriviLog($"Eccezione in sendOfflineOrderReq:{Environment.NewLine}{exc}");
}
// restituisco ok
return answ;
}
/// <summary>
/// Verifica lo stato di una richiesta di esecuzione
/// </summary>
/// <param name="OffOrderID">OfflineOrder di cui si chiede processing</param>
/// <param name="note">note opzionali</param>
/// <returns></returns>
public static bool checkOfflineOrderReq(int OffOrderID)
{
bool answ = false;
string typeSearch = "OffOrdCalculation";
string keyEnv = "";
// recupero lista dei vari task APERTI...
KeyValuePair<string, string>[] 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))
{
DataLayer.man.taOffOL.updateDrawing(OffOrderID, offOrder.DrawingPath, offOrder.CncPath);
}
}
// restituisco ok
return answ;
}
/// <summary>
/// Resetto i dati PRIMA di salvare i nuovi dati dal nesting
/// </summary>
/// <param name="BatchID"></param>
/// <param name="BunkList"></param>
public static void resetPrevDataFromNesting(int BatchID)
{
//elimino dati child MA NON il batch...
DataLayer.man.taBL.deleteTree(BatchID, 0);
}
/// <summary>
/// Salvo dati Bunks/Sheets/Parts ricevuti da Nesting (COMPETATO)
/// </summary>
/// <param name="BatchID"></param>
/// <param name="BunkList"></param>
public static void updateBunksFromNesting(int BatchID, List<NestBunk> 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);
}
}
// ora salvo ANCHE i remnants dello sheet... SE ci sono
if (sheet.Remnant != null)
{
DataLayer.man.taRem.insertAndReturn(BatchID, sheet.MatId, currSheet.SheetID, sheet.Remnant.L_mm, sheet.Remnant.W_mm, false);
}
}
}
}
}
}
}
}
/// <summary>
/// Salvo dati su PartList ricevuti da Nesting (COMPETATO)
/// </summary>
/// <param name="BatchID"></param>
/// <param name="BinList"></param>
public static void updateBinsFromNesting(int BatchID, List<NestBin> 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);
}
}
}
}
}
}
/// <summary>
/// Salvo dati su PartList ricevuti da Nesting (COMPETATO)
/// </summary>
/// <param name="BatchID"></param>
/// <param name="CartList"></param>
public static void updateCartsFromNesting(int BatchID, List<NestCart> 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);
}
}
}
}
}
}
/// <summary>
/// Salvo dati su PartList ricevuti da Nesting (stima)
/// </summary>
/// <param name="PartList"></param>
public static void updatePartsFromNesting(List<Part> 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);
}
}
/// <summary>
/// Recupera le operazioni di PostProcessing, esempio:
/// - T-Nut
/// - Round
/// - Chop
/// </summary>
/// <param name="optParameters"></param>
/// <returns></returns>
public static string getPostProcList(Dictionary<string, string> 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;
}
/// <summary>
/// Recupera le operazioni RICHIESTE a valle
/// - Paint
/// - Assembly
/// - SecOp
/// </summary>
/// <param name="optParameters"></param>
/// <returns></returns>
public static string getProcessesReq(Dictionary<string, string> 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;
}
/// <summary>
/// Recupera file pdf
/// </summary>
/// <param name="optParameters"></param>
/// <returns></returns>
public static string getPdfFilePath(Dictionary<string, string> optParameters)
{
string answ = "";
if (optParameters.ContainsKey("PdfLink"))
{
answ = optParameters["PdfLink"];
}
return answ;
}
#endregion
#region metodi helper di conversione
/// <summary>
/// Helper x serializzare l'oggetto
/// </summary>
/// <param name="currData"></param>
/// <returns></returns>
public static string serializeTakt(Takt currData)
{
string answ = JsonConvert.SerializeObject(currData);
return answ;
}
/// <summary>
/// Helper x deserializzare l'oggetto
/// </summary>
/// <param name="rawData"></param>
/// <returns></returns>
public static Takt deserializeTakt(string rawData)
{
Takt answ = JsonConvert.DeserializeObject<Takt>(rawData);
return answ;
}
/// <summary>
/// Deserializza un ordine offline
/// </summary>
/// <param name="rawData"></param>
/// <returns></returns>
public static nestReplyOffOrd deserializeOfflineOrder(string rawData)
{
nestReplyOffOrd answ = null;
try
{
answ = JsonConvert.DeserializeObject<nestReplyOffOrd>(rawData);
}
catch
{ }
return answ;
}
#endregion
#region metodi x data persistence
/// <summary>
/// Salvo il Takt inviato
/// </summary>
/// <param name="origin">Origine del dato: SERV / PROD / NEST</param>
/// <param name="currData"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Leggo il Takt inviato
/// </summary>
/// <param name="origin">Origine del dato: SERV / PROD / NEST</param>
/// <param name="currData"></param>
/// <returns></returns>
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
/// <summary>
/// Salva per 5 sec la richiesta di reload delle pagine MachineUnload
/// </summary>
public static void setReloadMU()
{
memLayer.ML.setRSV(redMachUnloadForce, "true", 5);
}
/// <summary>
/// Esegue richieste lettura da PROD
/// </summary>
public static void procProdReadReq()
{
// !!!FIXME!!!
}
/// <summary>
/// Esegue richieste scrittura da PROD
/// </summary>
public static void procProdWriteReq()
{
// !!!FIXME!!!
}
/// <summary>
/// Fornisce il prossimo TAKT da elaborare oppure null se non ce ne fossero altri da elaborare per la data CORRENTE
/// </summary>
/// <returns></returns>
public Takt prodGetNextTakt()
{
return null;
}
/// <summary>
/// Chiave primo bunk su redis
/// </summary>
protected static string redFirstBunkKey = $"{redProdReq}:FirstBunk";
/// <summary>
/// Chiave primo bunk su redis
/// </summary>
protected static string redAllNextBunkKey = $"{redProdReq}:NextBunk";
/// <summary>
/// TTL standard x dati da scambiare con PROD (30 gg)
/// </summary>
protected static int ttlProdData = 3600 * 24 * 30;
/// <summary>
/// Chiave primo bunk su redis
/// </summary>
protected static string redNextBunkKey(int BunkID)
{
return $"{redProdReq}:NextBunk:{BunkID}";
}
/// <summary>
/// Chiave bunk corrente su redis
/// </summary>
/// <param name="machine"></param>
/// <returns></returns>
protected static string redCurrBunkTabKey(string machine)
{
string answ = "";
if (string.IsNullOrEmpty(machine))
{
answ = $"{redProdReq}:CurrBunks";
}
else
{
answ = $"{redProdReq}:CurrBunks:{machine}";
}
return answ;
}
/// <summary>
/// Chiave sheets correnti su redis
/// </summary>
/// <param name="machine"></param>
/// <returns></returns>
protected static string redCurrSheetTabKey(string machine)
{
string answ = "";
if (string.IsNullOrEmpty(machine))
{
answ = $"{redProdReq}:CurrSheets";
}
else
{
answ = $"{redProdReq}:CurrSheets:{machine}";
}
return answ;
}
/// <summary>
/// Chiave BATCH corrente su redis
/// </summary>
/// <param name="machine"></param>
/// <returns></returns>
protected static string redCurrBatchId(string machine)
{
string answ = "";
if (string.IsNullOrEmpty(machine))
{
answ = $"{redProdReq}:CurrBatchID";
}
else
{
answ = $"{redProdReq}:CurrBatchID:{machine}";
}
return answ;
}
/// <summary>
/// Chiave Bunk corrente su redis
/// </summary>
/// <param name="machine"></param>
/// <returns></returns>
protected static string redCurrBunkId(string machine)
{
string answ = "";
if (string.IsNullOrEmpty(machine))
{
answ = $"{redProdReq}:CurrBunkID";
}
else
{
answ = $"{redProdReq}:CurrBunkID:{machine}";
}
return answ;
}
/// <summary>
/// Chiave Sheets corrente su redis
/// </summary>
/// <param name="machine"></param>
/// <returns></returns>
protected static string redCurrSheetId(string machine)
{
string answ = "";
if (string.IsNullOrEmpty(machine))
{
answ = $"{redProdReq}:CurrSheetID";
}
else
{
answ = $"{redProdReq}:CurrSheetID:{machine}";
}
return answ;
}
/// <summary>
/// Resetto in REDIS i dati di bunk (corrente e successivi)
/// </summary>
public static void resetRedisBunkData(string machine)
{
resetCurrBunk();
resetCurrSheet();
setCurrBatchId(machine, 0);
setCurrBunkId(machine, 0);
setCurrSheetId(machine, 0);
redisFirstBunk = null;
}
/// <summary>
/// Cache redis del BunkID in lavorazione sulla macchina
/// <param name="machine"></param>
/// </summary>
public static int getCurrBatchId(string macchina)
{
int answ = -1;
string rawData = memLayer.ML.getRSV(redCurrBatchId(macchina));
int.TryParse(rawData, out answ);
return answ;
}
/// <summary>
/// Salvataggio in redis del BunkID in lavorazione sulla macchina
/// </summary>
public static void setCurrBatchId(string macchina, int BatchID)
{
memLayer.ML.setRSV(redCurrBatchId(macchina), BatchID.ToString());
}
/// <summary>
/// Cache redis del BunkID in lavorazione sulla macchina
/// <param name="machine"></param>
/// </summary>
public static int getCurrBunkId(string macchina)
{
int answ = -1;
string rawData = memLayer.ML.getRSV(redCurrBunkId(macchina));
int.TryParse(rawData, out answ);
return answ;
}
/// <summary>
/// Salvataggio in redis del BunkID in lavorazione sulla macchina
/// </summary>
public static void setCurrBunkId(string macchina, int BunkID)
{
memLayer.ML.setRSV(redCurrBunkId(macchina), BunkID.ToString());
}
/// <summary>
/// Cache redis del SheetID in lavorazione sulla macchina
/// <param name="machine"></param>
/// </summary>
public static int getCurrSheetId(string macchina)
{
int answ = -1;
string rawData = memLayer.ML.getRSV(redCurrSheetId(macchina));
int.TryParse(rawData, out answ);
return answ;
}
/// <summary>
/// Salvataggio in redis del SheetID in lavorazione sulla macchina
/// </summary>
public static void setCurrSheetId(string macchina, int SheetID)
{
memLayer.ML.setRSV(redCurrSheetId(macchina), SheetID.ToString());
}
/// <summary>
/// Cache redis del PRIMO bunk da lavorare
/// </summary>
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<ProdBunk>(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();
}
}
}
/// <summary>
/// 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
/// </summary>
/// <param name="BatchID"></param>
/// <returns></returns>
public static void updateBatchPosition(int BatchID)
{
// chiamo stored x checkPosition
DataLayer.man.taBL.checkPosition(BatchID);
}
/// <summary>
/// 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
/// </summary>
/// <param name="BunkID"></param>
/// <returns></returns>
public static void updateBatchPositionByBunk(int BunkID)
{
// recupero il BatchID
DS_App.StackListDataTable tabBunk = DataLayer.man.taSTL.getByKey(BunkID);
if (tabBunk.Count > 0)
{
try
{
int BatchID = tabBunk[0].BatchID;
// chiamo procedura di check sull'intero bunk
updateBatchPosition(BatchID);
}
catch
{ }
}
}
/// <summary>
/// Recupero da Redis del SUCCESSIVO bunk da lavorare
/// </summary>
/// <param name="currBunkId"></param>
/// <returns></returns>
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<ProdBunk>(rawData);
}
catch
{ }
}
return answ;
}
/// <summary>
/// Salvo in Redis il SUCCESSIVO bunk da lavorare
/// </summary>
/// <param name="currBunkId"></param>
/// <param name="value"></param>
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), "");
}
}
/// <summary>
/// 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
/// </summary>
/// <param name="codPost"></param>
/// <returns></returns>
public static SheetWorkList prodGetSheetWorkList(string codPost)
{
// init out
SheetWorkList answ = null;
// recupero batch corrente
DS_App.BatchListDataTable currBatch = DataLayer.man.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 = DataLayer.man.taSHL.getCurrentByBatch(batchRow.BatchID);
List<DS_App.SheetListRow> sheetList = new List<DS_App.SheetListRow>();
// 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;
}
/// <summary>
/// Rranscodifica dati da format DB a formato PROD
/// </summary>
/// <param name="sheetList">Elenco fogli da DB</param>
/// <returns></returns>
private static SheetWorkList convertSheetWorkList(List<DS_App.SheetListRow> sheetList)
{
SheetWorkList answ;
List<ProdSheetExt> elSheet = new List<ProdSheetExt>();
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;
}
/// <summary>
/// Restituisce il BUNK che è il primo della lista:
/// - posizione = 3 (ho letto da webApp il BUNK e preso in carico)
/// - NumSheet > NumSheetUnload
/// - Ordinato per StackIndex (crescente) x avere il più VECCHIO
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// BUNK corrente (x ora copia di first, poi sarà quello SELEZIONATO tra quelli SELEZIONABILI)
/// </summary>
/// <returns></returns>
public static DS_App.StackListRow getCurrBunk(string machine = "WRK001")
{
DS_App.StackListRow answ = null;
DS_App.StackListDataTable tabBunk = null;
// cerco in cache....
if (getCurrBunkTab(machine) != null)
{
tabBunk = getCurrBunkTab(machine);
}
else
{
tabBunk = DataLayer.man.taSTL.getLoaded();
// salvo in redis
setCurrBunkTab(machine, tabBunk);
}
if (tabBunk != null && tabBunk.Count > 0)
{
answ = tabBunk[0];
}
return answ;
}
/// <summary>
/// resetto curr bunk
/// </summary>
/// <param name="machine"></param>
public static void resetCurrBunk(string machine = "WRK001")
{
// svuoto"
memLayer.ML.redFlushKey(redCurrBunkTabKey(machine));
}
/// <summary>
/// lettura currBunk table da cache
/// </summary>
/// <param name="machine"></param>
/// <returns></returns>
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<DS_App.StackListDataTable>(rawData);
}
catch
{ }
}
return answ;
}
/// <summary>
/// salvataggio inc ache currBunk table
/// </summary>
/// <param name="machine"></param>
/// <param name="tabBunks"></param>
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);
}
/// <summary>
/// PackList corrente (running in KIT)
/// </summary>
/// <returns></returns>
public static DS_App.PackListRow getCurrPackList()
{
DS_App.PackListRow answ = null;
var tabPLD = DataLayer.man.taPL.getRunning();
if (tabPLD.Count > 0)
{
answ = tabPLD[0];
}
return answ;
}
/// <summary>
/// Recupera lo sheet corrente da un BUNK come quello in status 5...
/// </summary>
/// <param name="BatchID"></param>
/// <param name="machine"></param>
/// <returns></returns>
public static DS_App.SheetListRow getCurrSheet(int BatchID, string machine)
{
DS_App.SheetListRow answ = null;
if (BatchID > 0)
{
try
{
DS_App.SheetListDataTable tabSheets = null;
// cerco in cache....
if (getCurrSheetTab(machine) != null)
{
tabSheets = getCurrSheetTab(machine);
}
else
{
// recupero sheet corrente da Bunk...
tabSheets = DataLayer.man.taSHL.getByMLStatus(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;
}
/// <summary>
/// resetto curr sheets
/// </summary>
/// <param name="machine"></param>
public static void resetCurrSheet(string machine = "WRK001")
{
// svuoto"
memLayer.ML.redFlushKey(redCurrSheetTabKey(machine));
}
/// <summary>
/// Recupero da redis tab fogli correnti
/// </summary>
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<DS_App.SheetListDataTable>(rawData);
}
catch
{ }
}
return answ;
}
/// <summary>
/// Salvataggio in redis tab fogli correnti
/// </summary>
/// <param name="machine"></param>
/// <param name="tabella"></param>
protected static void setCurrSheetTab(string machine, DS_App.SheetListDataTable tabella)
{
string rawData = JsonConvert.SerializeObject(tabella);
// TTL 5 sec
memLayer.ML.setRSV(redCurrSheetTabKey(machine), rawData, 2);
}
/// <summary>
/// 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
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// Recupera e transcodifica DA DB i dati di UN SINGOLO bunk
/// </summary>
/// <param name="currBunk"></param>
/// <returns></returns>
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<ProdSheet> elSheet = new List<ProdSheet>();
// recupero gli sheets di questo stack...
DS_App.SheetListDataTable tabSheets = DataLayer.man.taSHL.getByStack(currBunk.StackID);
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;
}
/// <summary>
/// Recupera e transcodifica DA DB i dati di UN SINGOLO bunk
/// </summary>
/// <param name="currBunk"></param>
/// <returns></returns>
public static ProdBunk prodGetBunk(int StackID)
{
ProdBunk answ = null;
List<ProdSheet> elSheet = new List<ProdSheet>();
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;
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;
}
/// <summary>
/// ID del BUNK correntemente in processing per ML (MachineLoad)
/// </summary>
public static string taktMLCurrBunk
{
get
{
return memLayer.ML.getRSV(redMLCurrBunk);
}
set
{
memLayer.ML.setRSV(redMLCurrBunk, value);
}
}
#endregion
#region metodi x UNLOAD
/// <summary>
/// Calcola area REDIS per FOGLIO in fase di scarico
/// </summary>
/// <param name="SheetID"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Calcola area REDIS per BUNK in fase di scarico
/// </summary>
/// <param name="BunkID"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Recupera da REDIS info indice revisione x BUNK (cambio foglio)
/// </summary>
/// <param name="BunkID"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Aggiorna revisione indice sheet x BUNK (cambio foglio)
/// </summary>
/// <param name="BunkID"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Svuota elenco pezzi nella postazione di unload
/// </summary>
/// <param name="SheetID"></param>
/// <returns></returns>
public bool resetSheetUnload(int SheetID = 0)
{
bool answ = false;
try
{
memLayer.ML.redFlushKey(machineUnloadArea(SheetID));
answ = true;
}
catch
{ }
return answ;
}
/// <summary>
///
/// </summary>
/// <param name="sheetID"></param>
/// <returns></returns>
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);
// solo se sheet > 0...
if (sheetID > 0)
{
try
{
// elenco items da foglio!!!
var tabItems = DataLayer.man.taIL.getBySheet(sheetID);
List<string> itemsAll = new List<string>();
List<string> itemsDepo = new List<string>();
List<string> itemsCart = new List<string>();
List<string> itemsBin = new List<string>();
List<string> itemsSecOp = new List<string>();
List<string> itemsScrap = new List<string>();
List<string> itemsSelect = new List<string>();
//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;
}
/// <summary>
/// Registra che un dato ITEM è stato prelevato in fase di scarico da ID foglio + datamatrix
/// </summary>
/// <param name="sheetID">ID foglio</param>
/// <param name="deviceId">Cod del device di scarico</param>
/// <param name="itemDtmx">Cod datamatrix ITEM</param>
/// <returns></returns>
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<string, string> dictData = new Dictionary<string, string>();
try
{
if (!string.IsNullOrEmpty(rawData))
{
dictData = JsonConvert.DeserializeObject<Dictionary<string, string>>(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;
}
/// <summary>
/// Registra che un dato ITEM è stato prelevato in fase di scarico da ID foglio + datamatrix
/// </summary>
/// <param name="sheetID">ID foglio</param>
/// <param name="deviceId">Cod del device di scarico</param>
/// <returns></returns>
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<string, string> dictData = JsonConvert.DeserializeObject<Dictionary<string, string>>(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;
}
/// <summary>
/// Processa elenco items e salva in redis valori x css, elenchi, ...
/// </summary>
/// <param name="currCss">CSS corrente</param>
/// <param name="redKeyBase">HASH abse x area REDIS</param>
/// <param name="varName">nome variabile x elenco items</param>
/// <param name="itemList">Elenco items specifici</param>
/// <param name="dataCacheTTL">TTL della cache x salvataggio valori</param>
/// <returns></returns>
public static string updateCssByItemList(string currCss, string redKeyBase, string varName, List<string> 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;
}
/// <summary>
/// Processa elenco items e salva in redis valori x css, elenchi, ...
/// </summary>
/// <param name="currCss">CSS corrente</param>
/// <param name="redKeyBase">HASH abse x area REDIS</param>
/// <param name="varName">nome variabile x elenco items</param>
/// <param name="dataCacheTTL">TTL della cache x salvataggio valori</param>
/// <returns></returns>
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<string, string> dictData = JsonConvert.DeserializeObject<Dictionary<string, string>>(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;
}
/// <summary>
/// IP del device
/// </summary>
/// <returns></returns>
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"];
}
/// <summary>
/// Calcola area REDIS per MACCHINA
/// </summary>
/// <param name="SheetID"></param>
/// <returns></returns>
public static string machineArea(string machineCod)
{
string answ = memLayer.ML.redHash($"currMachineData:{machineCod}");
return answ;
}
/// <summary>
/// Recupera prossimo batch da DB (NEXT... da db x status... ok SOLO x singola macchina)
/// </summary>
protected int getNextBatch
{
get
{
int answ = 0;
try
{
var currData = DataLayer.man.taBL.getNextAvailable();
if (currData.Count > 0)
{
answ = currData[0].BatchID;
}
}
catch
{ }
return answ;
}
}
/// <summary>
/// Recupera SHEET da batch e sstati permessi...
/// </summary>
/// <param name="BatchID"></param>
/// <param name="minVal"></param>
/// <param name="maxVal"></param>
/// <returns></returns>
protected int getSheetIdByBatch(int BatchID, int minVal, int maxVal)
{
int answ = 0;
try
{
var tabSheet = DataLayer.man.taSHL.getByMLStatus(BatchID, minVal, maxVal);
if (tabSheet.Count > 0)
{
answ = tabSheet[0].SheetID;
}
}
catch
{ }
return answ;
}
/// <summary>
/// Fornisce un dictionary di valori ATTUALI per una specifica macchina
/// </summary>
/// <param name="machineCod"></param>
/// <returns></returns>
public Dictionary<string, string> getCurrMachineData(string machineCod)
{
Dictionary<string, string> answ = new Dictionary<string, string>();
// cerco in REDIS
string rawData = memLayer.ML.getRSV(machineArea(machineCod));
if (!string.IsNullOrEmpty(rawData))
{
answ = JsonConvert.DeserializeObject<Dictionary<string, string>>(rawData);
}
else
{
// recupero batch e sheet...
int batchId = getNextBatch;
// 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).ToString());
answ.Add("SheetID_print", getSheetIdByBatch(batchId, 1, 2).ToString());
answ.Add("SheetID_work", getSheetIdByBatch(batchId, 2, 3).ToString());
answ.Add("SheetID_unload", getSheetIdByBatch(batchId, 3, 5).ToString());
// serializzo e salvo!
saveMachineData(machineCod, answ);
}
// restituisco!
return answ;
}
/// <summary>
/// Salvataggio array dati di una macchina
/// </summary>
/// <param name="machineCod"></param>
/// <param name="paramsArray"></param>
/// <returns></returns>
public bool saveMachineData(string machineCod, Dictionary<string, string> 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;
}
/// <summary>
/// Fornisce un dictionary di valori ATTUALI per una specifica macchina
/// </summary>
/// <param name="machineCod"></param>
/// <param name="Key"></param>
/// <param name="Val"></param>
/// <returns></returns>
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;
}
#endregion
#region metodi per SecScreen
public static int getSecScreenCode()
{
int answ = 0;
Random rnd = new Random();
answ = rnd.Next(1000000);
return answ;
}
/// <summary>
/// Restitusice il path del PDF richeisto su una data SecScreen come salvato su REDIS
/// </summary>
/// <param name="secScreenCode">cod schermo, formato SSC000000</param>
/// <returns></returns>
public static string getSecScreenRequest(string secScreenCode)
{
string answ = "";
// recupero ultima call
string redKey = $"{redSecScreenReq}:{secScreenCode}";
answ = memLayer.ML.getRSV(redKey);
return answ;
}
/// <summary>
/// Salva su REDIS richiesta visualizzaizone SecondScreen x
/// </summary>
/// <param name="secScreenCode">cod schermo, formato SSC000000</param>
/// <param name="filePath">Path file richiesto (pdf)</param>
/// <param name="ttl_sec">durata in redis della richiesta</param>
/// <returns></returns>
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;
}
#endregion
}
}