Files
Mapo-IOB-WIN/IOB-WIN-NEXT/IobSql/SqlServLantek.cs
T
Samuele Locatelli 8bb0f158b5 SPLIT PROGETTO!!!
- 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
2024-12-20 10:16:32 +01:00

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 --&gt; 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
}
}