8bb0f158b5
- proj di base con le 2 form da ereditare - progetto globale che contiene TUTTI gli adapter (pronto a venire spezzettato - gettate le basi x "portare fuori" i vari componenti oppure fare compilazione condizonale
523 lines
22 KiB
C#
523 lines
22 KiB
C#
using EgwProxy.SqlDb.Controllers;
|
|
using EgwProxy.SqlDb.DbModels;
|
|
using IOB_UT_NEXT;
|
|
using MapoSDK;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Net.NetworkInformation;
|
|
using static IOB_UT_NEXT.CustomObj;
|
|
|
|
namespace IOB_WIN_NEXT.IobSql
|
|
{
|
|
/// <summary>
|
|
/// Adapter specializzato per LANTEK e le chiamate tramite DB per i dati
|
|
/// - PODL (ordini MES --> MACCHINA)
|
|
/// - ProdLog (da NestingDaLantek + RigheNestingDaLantek)
|
|
/// </summary>
|
|
|
|
public class SqlServLantek : Iob.GenericNext
|
|
{
|
|
#region Public Constructors
|
|
|
|
/// <summary>
|
|
/// Costruttore dell'IOB DB LANTEK
|
|
/// </summary>
|
|
/// <param name="caller">AdapterForm chiamante</param>
|
|
/// <param name="IOBConf">Configurazione IOB per avvio</param>
|
|
public SqlServLantek(AdapterFormNext caller, IobConfiguration IOBConf) : base(caller, IOBConf)
|
|
{
|
|
DateTime adesso = DateTime.Now;
|
|
string SyncStateServ = getOptPar("SyncStateServer");
|
|
string SyncStateDb = getOptPar("SyncStateDb");
|
|
string SyncStateUser = getOptPar("SyncStateUser");
|
|
string SyncStatePwd = getOptPar("SyncStatePwd");
|
|
string SyncStateCTout = getOptPar("SyncStateCTout");
|
|
string VetoReadSec = getOptPar("VetoReadSec");
|
|
string VetoSyncSec = getOptPar("VetoSyncSec");
|
|
string sFullPodlUrl = getOptPar("FullPodlUrl");
|
|
|
|
setupSpecialParams();
|
|
|
|
string connSyncState = $"data source={SyncStateServ};initial catalog={SyncStateDb};persist security info=True;user id={SyncStateUser};password={SyncStatePwd};MultipleActiveResultSets=True;App=IOB-WIN-NEXT";
|
|
|
|
// gestione command timeout da https://erikej.github.io/sqlclient/2020/10/26/sqlclient-commandtimeout-preview.html
|
|
if (!string.IsNullOrEmpty(SyncStateCTout))
|
|
{
|
|
connSyncState = $"{connSyncState};Command Timeout={SyncStateCTout}";
|
|
}
|
|
if (!string.IsNullOrEmpty(VetoReadSec))
|
|
{
|
|
int.TryParse(VetoReadSec, out vetoReadDbSec);
|
|
}
|
|
if (!string.IsNullOrEmpty(VetoSyncSec))
|
|
{
|
|
int.TryParse(VetoSyncSec, out VetoSyncDbSec);
|
|
}
|
|
if (!string.IsNullOrEmpty(sFullPodlUrl))
|
|
{
|
|
bool.TryParse(sFullPodlUrl, out FullPodlUrl);
|
|
}
|
|
|
|
// avvio DB controller
|
|
dbProxy = new DbController(connSyncState);
|
|
|
|
lastPING = DateTime.Now.AddHours(-1);
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Implementazione custom esecuzione task specifici
|
|
/// </summary>
|
|
/// <param name="task2exe"></param>
|
|
/// <returns></returns>
|
|
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
|
|
{
|
|
DateTime adesso = DateTime.Now;
|
|
// unico task ammissibile: fare un SYNC forzato...
|
|
Dictionary<string, string> taskDone = new Dictionary<string, string>();
|
|
if (task2exe != null)
|
|
{
|
|
// controllo se memMap != null...
|
|
if (memMap != null)
|
|
{
|
|
bool taskOk = false;
|
|
string taskVal = "";
|
|
// cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4
|
|
foreach (var item in task2exe)
|
|
{
|
|
taskOk = false;
|
|
taskVal = "";
|
|
// converto richiesta in enum...
|
|
taskType tName = taskType.nihil;
|
|
Enum.TryParse(item.Key, out tName);
|
|
// controllo sulla KEY...
|
|
switch (tName)
|
|
{
|
|
case taskType.setComm:
|
|
case taskType.syncDbData:
|
|
lgInfo($"executeTasks --> {tName}");
|
|
// per prima cosa recupero elenco PODL attivi x la macchina
|
|
List<PODLModel> listaPODL = new List<PODLModel>();
|
|
bool okPodl = false;
|
|
var rawListPODL = callUrl(urlGetCurrPODL, false);
|
|
if (!string.IsNullOrEmpty(rawListPODL))
|
|
{
|
|
try
|
|
{
|
|
listaPODL = JsonConvert.DeserializeObject<List<PODLModel>>(rawListPODL);
|
|
okPodl = listaPODL.Count > 0;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lg.Error($"Errore: chiamata elenco PODL ha restituito errore{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lg.Error($"Errore: chiamata elenco PODL ({urlGetCurrPODL}) ha restituito valore vuoto");
|
|
}
|
|
if (okPodl)
|
|
{
|
|
//mando elenco PODL...
|
|
List<MesPODLReqModel> CurrPodlReq = listaPODL
|
|
.Select(x => new MesPODLReqModel()
|
|
{
|
|
Attivabile = x.Attivabile,
|
|
CodArticolo = x.CodArticolo,
|
|
CodCli = x.CodCli,
|
|
CodGruppo = x.CodGruppo,
|
|
DueDate = x.DueDate ?? DateTime.Now,
|
|
IdxMacchina = x.IdxMacchina,
|
|
IdxODL = x.IdxOdl,
|
|
IdxPromessa = x.IdxPromessa,
|
|
InsertDate = x.InsertDate,
|
|
KeyBCode = x.KeyBCode,
|
|
KeyRichiesta = x.KeyRichiesta,
|
|
Note = x.Note,
|
|
NumPezzi = x.NumPezzi,
|
|
Priorita = x.Priorita,
|
|
PzPallet = x.PzPallet,
|
|
TCAssegnato = x.Tcassegnato
|
|
})
|
|
.ToList();
|
|
// scrivo i record richiesti
|
|
bool fatto = dbProxy.MesPodlWriteReq(CurrPodlReq);
|
|
if (fatto)
|
|
{
|
|
taskVal = $"EXECUTED task: {item.Key} / {item.Value}";
|
|
// registro evento chiamata scrittura in syncState...
|
|
string tabName = item.Key;
|
|
var currSyncState = elencoSyncState.FirstOrDefault(x => x.TableName == tabName);
|
|
// verifico x registrare azione
|
|
if (currSyncState == null)
|
|
{
|
|
currSyncState = new SyncStateModel()
|
|
{
|
|
LastIdx = 0,
|
|
LastUpdate = adesso,
|
|
TableName = tabName,
|
|
Note = "Init"
|
|
};
|
|
}
|
|
else
|
|
{
|
|
var lastRec = CurrPodlReq.OrderBy(x => x.IdxPromessa).LastOrDefault();
|
|
currSyncState.LastIdx = lastRec != null ? lastRec.IdxPromessa : -1;
|
|
currSyncState.Note = $"Esecuzione {tabName} per {CurrPodlReq.Count} rec | last code: {currSyncState.LastIdx}";
|
|
currSyncState.LastUpdate = adesso;
|
|
}
|
|
// salvo sync...
|
|
dbProxy.SyncStateUpsert(currSyncState);
|
|
}
|
|
|
|
// effettua sync scrivendo i dati in export (PODL)
|
|
execExportAll();
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
taskVal = $"IobSqlServLantek | taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
|
|
lgInfo($"IobSqlServLantek | chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
|
|
break;
|
|
}
|
|
// aggiungo task!
|
|
taskDone.Add(item.Key, taskVal);
|
|
}
|
|
}
|
|
}
|
|
lastReadPLC = DateTime.Now;
|
|
return taskDone;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recupero dati dinamici... FAKE!
|
|
/// </summary>
|
|
public override Dictionary<string, string> getDynData()
|
|
{
|
|
DateTime adesso = DateTime.Now;
|
|
|
|
// dizionario vuoto / gestito da altro adapter file-based
|
|
Dictionary<string, string> outVal = new Dictionary<string, string>();
|
|
|
|
lastReadPLC = DateTime.Now;
|
|
return outVal;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua processing CUSTOM:
|
|
/// - esegue tutti gli import
|
|
/// </summary>
|
|
public override void processCustomTaskLF()
|
|
{
|
|
lgInfo($"Richiesto processCustomTaskLF");
|
|
// effettua sync
|
|
execExportAll();
|
|
execImportAll();
|
|
lastReadPLC = DateTime.Now;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
|
|
/// aggiornare x display in form</paramref>
|
|
/// </summary>
|
|
public override void readSemafori(ref newDisplayData currDispData)
|
|
{
|
|
DateTime adesso = DateTime.Now;
|
|
if (connectionOk)
|
|
{
|
|
// controllo veto checkDB
|
|
if (adesso > vetoDataRead)
|
|
{
|
|
// predispongo prox veto...
|
|
vetoDataRead = adesso.AddSeconds(vetoReadDbSec);
|
|
if (adesso > vetoDataSync)
|
|
{
|
|
// effettua sync
|
|
execImportAll();
|
|
vetoDataSync = adesso.AddSeconds(VetoSyncDbSec);
|
|
}
|
|
|
|
// semaforo
|
|
currDispData.semIn = Semaforo.SV;
|
|
// recupero syncState
|
|
elencoSyncState = dbProxy.SyncStateGetAll();
|
|
// verifico ProdData e processo
|
|
bool sentProdData = processProdDataTable(adesso);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
B_input = 0;
|
|
currDispData.semIn = Semaforo.SR;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override connessione
|
|
/// </summary>
|
|
public override void tryConnect()
|
|
{
|
|
if (!connectionOk)
|
|
{
|
|
// controllo che il ping sia stato tentato almeno pingTestSec fa...
|
|
if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
|
|
{
|
|
if (verboseLog || periodicLog)
|
|
{
|
|
lgInfo("SqlDb LANTEK: ConnKO - tryConnect");
|
|
}
|
|
// in primis salvo data ping...
|
|
lastPING = DateTime.Now;
|
|
// se passa il ping faccio il resto...
|
|
if (testPingMachine == IPStatus.Success)
|
|
{
|
|
string szStatusConnection = "";
|
|
try
|
|
{
|
|
// ora provo connessione...
|
|
parentForm.commPlcActive = true;
|
|
if (dbProxy != null)
|
|
{
|
|
elencoSyncState = dbProxy.SyncStateDoImportAll();
|
|
|
|
if (elencoSyncState != null && elencoSyncState.Count > 0)
|
|
{
|
|
parentForm.commPlcActive = false;
|
|
connectionOk = true;
|
|
}
|
|
}
|
|
// refresh stato connessione!!!
|
|
if (connectionOk)
|
|
{
|
|
queueInEnabCurr = true;
|
|
if (adpRunning)
|
|
{
|
|
lgInfo("Connessione OK");
|
|
lastReadPLC = DateTime.Now;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError("Impossibile procedere, connessione mancante...");
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lgFatal($"Errore nella connessione all'adapter SqlDb LANTEK: {szStatusConnection}{Environment.NewLine}{exc}");
|
|
connectionOk = false;
|
|
lgInfo($"Eccezione in TryConnect, Adapter SqlDb LANTEK NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// loggo no risposta ping ...
|
|
connectionOk = false;
|
|
if (verboseLog || periodicLog)
|
|
{
|
|
lgInfo($"Attenzione: SqlDb LANTEK controllo PING fallito per IP {cIobConf.cncPingAddr}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
needRefresh = true;
|
|
}
|
|
}
|
|
|
|
public override void tryDisconnect()
|
|
{
|
|
// registro solo che è disconnesso
|
|
connectionOk = false;
|
|
queueInEnabCurr = false;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Protected Fields
|
|
|
|
protected bool FullPodlUrl = false;
|
|
protected int vetoReadDbSec = 3;
|
|
|
|
protected int VetoSyncDbSec = 20;
|
|
|
|
#endregion Protected Fields
|
|
|
|
#region Protected Properties
|
|
|
|
protected DbController dbProxy { get; set; } = null;
|
|
|
|
/// <summary>
|
|
/// Stato di sync delle tab gestite
|
|
/// </summary>
|
|
protected List<SyncStateModel> elencoSyncState { get; set; } = new List<SyncStateModel>();
|
|
|
|
#endregion Protected Properties
|
|
|
|
#region Private Methods
|
|
|
|
/// <summary>
|
|
/// Esegue task EXPORT (MES PODL to MACHINE)
|
|
/// </summary>
|
|
private void execExportAll()
|
|
{
|
|
Stopwatch sw = new Stopwatch();
|
|
sw.Start();
|
|
elencoSyncState = dbProxy.SyncStateDoExportAll();
|
|
sw.Stop();
|
|
DateTime adesso = DateTime.Now;
|
|
lastReadPLC = adesso;
|
|
lgInfo($"DB: esecuzione task dbProxy.SyncStateDoExportAll() in {sw.ElapsedMilliseconds} ms");
|
|
|
|
if (elencoSyncState != null)
|
|
{
|
|
// registro evento chiamata scrittura in syncState...
|
|
string tabName = "ExportAll";
|
|
var currSyncState = elencoSyncState.FirstOrDefault(x => x.TableName == tabName);
|
|
// verifico x registrare azione
|
|
if (currSyncState == null)
|
|
{
|
|
currSyncState = new SyncStateModel()
|
|
{
|
|
LastIdx = 0,
|
|
LastUpdate = adesso,
|
|
TableName = tabName,
|
|
Note = "Init"
|
|
};
|
|
}
|
|
else
|
|
{
|
|
// calcolo lastIDX valore da datetime
|
|
int valInt = -1;
|
|
var nowString = $"{adesso:HHmmss}";
|
|
int.TryParse(nowString, out valInt);
|
|
currSyncState.LastIdx = valInt;
|
|
currSyncState.Note = $"Esecuzione {tabName} | DT code: {currSyncState.LastIdx}";
|
|
currSyncState.LastUpdate = adesso;
|
|
}
|
|
// salvo sync...
|
|
dbProxy.SyncStateUpsert(currSyncState);
|
|
foreach (var item in elencoSyncState)
|
|
{
|
|
lgTrace($"TAB {item.TableName} | LastIdx {item.LastIdx} | Note {item.Note} | Last Upd {item.LastUpdate}");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue task IMPORT (MES PODL to MACHINE)
|
|
/// </summary>
|
|
private void execImportAll()
|
|
{
|
|
Stopwatch sw = new Stopwatch();
|
|
sw.Start();
|
|
elencoSyncState = dbProxy.SyncStateDoImportAll();
|
|
sw.Stop();
|
|
lastReadPLC = DateTime.Now;
|
|
lgInfo($"DB: esecuzione task dbProxy.SyncStateDoImportAll() in {sw.ElapsedMilliseconds} ms");
|
|
|
|
if (elencoSyncState != null)
|
|
{
|
|
foreach (var item in elencoSyncState)
|
|
{
|
|
lgTrace($"TAB {item.TableName} | LastIdx {item.LastIdx} | Note {item.Note} | Last Upd {item.LastUpdate}");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue processing + invio dati tab ProdData
|
|
/// </summary>
|
|
/// <param name="adesso"></param>
|
|
/// <returns></returns>
|
|
private bool processProdDataTable(DateTime adesso)
|
|
{
|
|
bool fatto = false;
|
|
string tabNameIn = "ProdData";
|
|
string tabNameOut = "ProdDataToMes";
|
|
// cerco info sui SignLog (ToMes e letti)
|
|
var currSignLogRead = elencoSyncState.FirstOrDefault(x => x.TableName == tabNameIn);
|
|
// se nullo inizializzo
|
|
if (currSignLogRead == null)
|
|
{
|
|
currSignLogRead = new SyncStateModel()
|
|
{
|
|
LastIdx = 0,
|
|
LastUpdate = adesso,
|
|
TableName = tabNameIn,
|
|
Note = "Init"
|
|
};
|
|
}
|
|
var currSignLogSent = elencoSyncState.FirstOrDefault(x => x.TableName == tabNameOut);
|
|
// se nullo inizializzo
|
|
if (currSignLogSent == null)
|
|
{
|
|
currSignLogSent = new SyncStateModel()
|
|
{
|
|
LastIdx = 0,
|
|
LastUpdate = adesso,
|
|
TableName = tabNameOut,
|
|
Note = "Init"
|
|
};
|
|
}
|
|
// verifica se ci siano dati da trasmettere (sui valori LastIdx)
|
|
if (currSignLogRead.LastIdx > currSignLogSent.LastIdx)
|
|
{
|
|
// recupero i dati dal DB...
|
|
var data2send = dbProxy.MachProdDataGetNew(currSignLogSent.LastIdx);
|
|
// se ho dati preparo invio
|
|
if (data2send != null && data2send.Count > 0)
|
|
{
|
|
foreach (var sLog2send in data2send)
|
|
{
|
|
if (sLog2send.Action == "StartOrd")
|
|
{
|
|
if (FullPodlUrl)
|
|
{
|
|
// se il record è apertura PODL chiamo apertura
|
|
trySetupPODL(sLog2send.IdxPodl, true, sLog2send.DtEve, DateTime.Now);
|
|
}
|
|
else
|
|
{
|
|
trySetupPODL(0);
|
|
}
|
|
}
|
|
else if (sLog2send.Action == "EndOrd")
|
|
{
|
|
// se il record è chiusura PODL chiamo chiusura... DOPO aver cercato
|
|
// PODL --> ODL
|
|
if (FullPodlUrl)
|
|
{
|
|
tryClosePODL(sLog2send.IdxPodl, sLog2send.DtEve, DateTime.Now);
|
|
}
|
|
else
|
|
{
|
|
tryClosePODL(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// aggiorno idx inviato...
|
|
currSignLogSent.Note = $"Updated from {currSignLogRead.LastIdx}";
|
|
currSignLogSent.LastUpdate = adesso;
|
|
currSignLogSent.LastIdx = currSignLogRead.LastIdx;
|
|
fatto = true;
|
|
}
|
|
|
|
// alla fine aggiorno i dati inviati!
|
|
dbProxy.SyncStateUpsert(currSignLogSent);
|
|
|
|
return fatto;
|
|
}
|
|
|
|
#endregion Private Methods
|
|
}
|
|
} |