5006 lines
206 KiB
C#
5006 lines
206 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using MP.Core.Conf;
|
|
using MP.Core.DTO;
|
|
using MP.Core.Objects;
|
|
using MP.Data;
|
|
using MP.Data.Controllers;
|
|
using MP.Data.DbModels;
|
|
using MP.Data.DbModels.Anag;
|
|
using MP.Data.MgModels;
|
|
using MP.Data.Services.IOC;
|
|
using MP.Data.Services.Mtc;
|
|
using Newtonsoft.Json;
|
|
using NLog;
|
|
using StackExchange.Redis;
|
|
using System.Data;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using static MP.Core.Objects.Enums;
|
|
|
|
namespace MP.IOC.Data
|
|
{
|
|
public class MpDataService : IDisposable
|
|
{
|
|
#region Public Constructors
|
|
|
|
public MpDataService(
|
|
IConfiguration configuration,
|
|
ILogger<MpDataService> logger,
|
|
IServiceScopeFactory scopeFactory,
|
|
IMtcSetupService mtcServ)
|
|
{
|
|
_logger = logger;
|
|
_logger.LogInformation("Starting MpDataService INIT");
|
|
_configuration = configuration;
|
|
_scopeFactory = scopeFactory;
|
|
|
|
// setup compoenti REDIS
|
|
redisConn = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("Redis"));
|
|
redisConnAdmin = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("RedisAdmin"));
|
|
redisDb = redisConn.GetDatabase();
|
|
BroadastMsgPipe = new MessagePipe(redisConn, Constants.BROADCAST_M_PIPE);
|
|
// leggo cache (lungo periodo e corto periodo)
|
|
int.TryParse(_configuration.GetValue<string>("ServerConf:redisLongTimeCache"), out redisLongTimeCache);
|
|
int.TryParse(_configuration.GetValue<string>("ServerConf:redisShortTimeCache"), out redisShortTimeCache);
|
|
Log.Info($"Redis INIT | redisLongTimeCache: {redisLongTimeCache} min | redisShortTimeCache {redisShortTimeCache} min");
|
|
|
|
// gestione scope factory
|
|
useFactory = _configuration.GetValue<bool>("ServerConf:useFactory");
|
|
// conf base x servizi condivisi IO/IOC
|
|
MpIoNS = _configuration.GetValue<string>("ServerConf:MpIoNS") ?? "MP";
|
|
Log.Info($"MpDataService | useFactory {useFactory} | MpIoNS {MpIoNS}");
|
|
|
|
// conf DB
|
|
string connStr = _configuration.GetConnectionString("MP.Data") ?? "";
|
|
if (string.IsNullOrEmpty(connStr))
|
|
{
|
|
Log.Error("DbController: ConnString empty!");
|
|
}
|
|
else
|
|
{
|
|
SpecDbController = new MpSpecController(configuration);
|
|
IocDbController = new MpIocController(configuration);
|
|
Log.Info("DbControllers INIT OK");
|
|
}
|
|
|
|
MtcService = mtcServ;
|
|
|
|
// conf mongo...
|
|
connStr = _configuration.GetConnectionString("mdbConnString") ?? "";
|
|
if (string.IsNullOrEmpty(connStr))
|
|
{
|
|
Log.Error("MongoController: ConnString empty!");
|
|
}
|
|
else
|
|
{
|
|
mongoController = new MpMongoController(configuration);
|
|
Log.Info("MongoController INIT OK");
|
|
}
|
|
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Properties
|
|
|
|
public static MpIocController IocDbController { get; set; } = null!;
|
|
public static MpMongoController mongoController { get; set; } = null!;
|
|
public static MpSpecController SpecDbController { get; set; } = null!;
|
|
public MessagePipe BroadastMsgPipe { get; set; } = null!;
|
|
|
|
/// <summary>
|
|
/// Dizionario dei tag configurati per IOB
|
|
/// </summary>
|
|
public Dictionary<string, List<TagData>> currTagConf { get; set; } = new Dictionary<string, List<TagData>>();
|
|
|
|
#endregion Public Properties
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Recupera eventuali azioni richieste
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<DisplayAction> ActionGetReq()
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
DisplayAction? result = null;
|
|
// cerco in redis...
|
|
RedisValue rawData = await redisDb.StringGetAsync(Utils.redisActionReq);
|
|
if (!string.IsNullOrEmpty($"{rawData}"))
|
|
{
|
|
result = JsonConvert.DeserializeObject<DisplayAction>($"{rawData}");
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"ActionGetReq Read from REDIS: {ts.TotalMilliseconds}ms");
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new DisplayAction();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Salva richiesta azione
|
|
/// </summary>
|
|
/// <param name="act2save"></param>
|
|
/// <returns></returns>
|
|
public bool ActionSetReq(DisplayAction? act2save)
|
|
{
|
|
bool fatto = false;
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
// cerco in redis...
|
|
string rawData = JsonConvert.SerializeObject(act2save);
|
|
// invio broadcast + salvo in redis
|
|
BroadastMsgPipe.saveAndSendMessage(Utils.redisActionReq, rawData);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"ActionSetReq REDIS send to broadcast + Write cache: {ts.TotalMilliseconds}ms");
|
|
return fatto;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica se sia da reinviare un tName alla macchina dall'elenco di quelli salvati (in
|
|
/// modalità upsert) se non scaduti
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="taskKey"></param>
|
|
/// <param name="taskVal"></param>
|
|
/// <returns></returns>
|
|
public bool AddCheckTask4Machine(string idxMacchina, taskType taskKey, string taskVal)
|
|
{
|
|
bool answ = false;
|
|
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
|
|
Log.Info($"addCheckTask4Machine idxMacchina: {idxMacchina} | taskKey: {taskKey} | taskVal: {taskVal}");
|
|
try
|
|
{
|
|
Dictionary<string, string> savedTask = mSavedTaskMacchina(idxMacchina);
|
|
// cerco valOut saved
|
|
string savedVal = savedTask[taskKey.ToString()];
|
|
// se ho un valOut != "" --> rimetto in coda di invio...
|
|
if (!string.IsNullOrEmpty(savedVal) && (savedVal != taskVal))
|
|
{
|
|
// leggo tName attuali...
|
|
Dictionary<string, string> currTask = mTaskMacchina(idxMacchina);
|
|
// rimetto in tName da eseguire...
|
|
currTask[taskKey.ToString()] = savedVal;
|
|
RedisSetHashDict(currHash, currTask);
|
|
answ = true;
|
|
Log.Info($"re-issued task4machine: idxMacchina: {idxMacchina} | taskKey: {taskKey} | savedVal: {savedVal}");
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in AddCheckTask4Machine{Environment.NewLine}{exc}");
|
|
}
|
|
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aggiunge un PARAMETRO OPZIONALE all'elenco di quelli salvati (in modalità upsert)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="taskKey"></param>
|
|
/// <param name="taskVal"></param>
|
|
/// <returns></returns>
|
|
public bool AddOptPar4Machine(string idxMacchina, string taskKey, string taskVal)
|
|
{
|
|
bool answ = false;
|
|
RedisKey currHash = Utils.RedKeyOptPar(idxMacchina, MpIoNS);
|
|
try
|
|
{
|
|
// leggo tName attuali...
|
|
var currVal = mOptParMacchina(idxMacchina);
|
|
// verifico se esista o se vada aggiunto...
|
|
if (currVal.ContainsKey(taskKey))
|
|
{
|
|
currVal[taskKey] = taskVal;
|
|
}
|
|
else
|
|
{
|
|
currVal.Add(taskKey, taskVal);
|
|
}
|
|
RedisSetHashDict(currHash, currVal);
|
|
answ = true;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in addOptPar4Machine{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aggiunge un tName all'elenco di quelli salvati (in modalità upsert)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="taskKey"></param>
|
|
/// <param name="taskVal"></param>
|
|
/// <returns></returns>
|
|
public bool AddTask4Machine(string idxMacchina, Enums.taskType taskKey, string taskVal)
|
|
{
|
|
bool answ = false;
|
|
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
|
|
var currSavedParHash = Utils.RedKeySavedTask2ExeMacc(idxMacchina, MpIoNS);
|
|
Dictionary<string, string> currTask = new Dictionary<string, string>();
|
|
Dictionary<string, string> savedTask = new Dictionary<string, string>();
|
|
try
|
|
{
|
|
// leggo tName attuali...
|
|
currTask = mTaskMacchina(idxMacchina);
|
|
if (currTask.ContainsKey($"{taskKey}"))
|
|
{
|
|
currTask[$"{taskKey}"] = taskVal;
|
|
}
|
|
else
|
|
{
|
|
currTask.Add($"{taskKey}", taskVal);
|
|
}
|
|
RedisSetHashDict(currHash, currTask);
|
|
answ = true;
|
|
Log.Info($"Task ADD | hash: {currHash} | idxMacchina: {idxMacchina} | taskKey: {taskKey} | taskVal: {taskVal}");
|
|
}
|
|
catch { }
|
|
// verifico in base al tipo di tName se fare backup...
|
|
switch (taskKey)
|
|
{
|
|
case Enums.taskType.setArt:
|
|
case Enums.taskType.setComm:
|
|
case Enums.taskType.setPzComm:
|
|
case Enums.taskType.setProg:
|
|
// leggo tName SALVATI attuali...
|
|
savedTask = mSavedTaskMacchina(idxMacchina);
|
|
savedTask[taskKey.ToString()] = taskVal;
|
|
RedisSetHashDict(currSavedParHash, savedTask);
|
|
answ = true;
|
|
break;
|
|
|
|
case Enums.taskType.endProd:
|
|
// salvo un DICT vuoto x resettare
|
|
savedTask = new Dictionary<string, string>();
|
|
RedisSetHashDict(currSavedParHash, savedTask);
|
|
answ = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aggiunge un set di task x macchina all'elenco di quelli salvati (in modalità upsert)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="taskKey"></param>
|
|
/// <param name="taskVal"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> AddTask4MacListAsync(string idxMacchina, Dictionary<Enums.taskType, string> taskDict)
|
|
{
|
|
bool answ = false;
|
|
bool needSaveParams = false;
|
|
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
|
|
var currSavedParHash = Utils.RedKeySavedTask2ExeMacc(idxMacchina, MpIoNS);
|
|
Dictionary<string, string> currTask = new Dictionary<string, string>();
|
|
Dictionary<string, string> savedTask = new Dictionary<string, string>();
|
|
|
|
// leggo valori attuali...
|
|
currTask = await mTaskMacchinaAsync(idxMacchina);
|
|
// verifico processing dei ricevuti
|
|
foreach (var item in taskDict)
|
|
{
|
|
if (currTask.ContainsKey($"{item.Key}"))
|
|
{
|
|
currTask[$"{item.Key}"] = item.Value;
|
|
}
|
|
else
|
|
{
|
|
currTask.Add($"{item.Key}", item.Value);
|
|
}
|
|
Log.Trace($"Task ADD | hash: {currHash} | idxMacchina: {idxMacchina} | taskKey: {item.Key} | taskVal: {item.Value}");
|
|
|
|
// verifico in base al tipo di tName se fare backup...
|
|
switch (item.Key)
|
|
{
|
|
case Enums.taskType.setArt:
|
|
case Enums.taskType.setComm:
|
|
case Enums.taskType.setPzComm:
|
|
case Enums.taskType.setProg:
|
|
// leggo tName SALVATI attuali...
|
|
savedTask = mSavedTaskMacchina(idxMacchina);
|
|
savedTask[item.Key.ToString()] = item.Value;
|
|
needSaveParams = true;
|
|
break;
|
|
|
|
case Enums.taskType.endProd:
|
|
// salvo un DICT vuoto x resettare
|
|
savedTask = new Dictionary<string, string>();
|
|
needSaveParams = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
// salvo!
|
|
await RedisSetHashDictAsync(currHash, currTask);
|
|
answ = true;
|
|
|
|
if (needSaveParams)
|
|
{
|
|
await RedisSetHashDictAsync(currSavedParHash, savedTask);
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Insert record allarme
|
|
/// </summary>
|
|
/// <param name="dtRif">Data evento</param>
|
|
/// <param name="idxMacchina">Idx macchina</param>
|
|
/// <param name="memAddress">area memoria</param>
|
|
/// <param name="memAddress">indice memoria</param>
|
|
/// <param name="memAddress">valOut status</param>
|
|
/// <param name="memAddress">valOut decodificato</param>
|
|
/// <returns></returns>
|
|
public async Task<bool> AlarmInsertAsync(DateTime dtRif, string idxMacchina, string memAddress, int memIndex, int statusVal, string valDecoded)
|
|
{
|
|
// aggiorno record sul DB
|
|
bool answ = await IocDbController.AlarmLogInsertAsync(dtRif, idxMacchina, memAddress, memIndex, statusVal, valDecoded);
|
|
|
|
return answ;
|
|
}
|
|
|
|
public async Task<List<ListValuesModel>> AnagStatiComm()
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
List<ListValuesModel>? result = new List<ListValuesModel>();
|
|
// cerco in redis...
|
|
RedisValue rawData = await redisDb.StringGetAsync(Utils.redisStatoCom);
|
|
if (!string.IsNullOrEmpty($"{rawData}"))
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<ListValuesModel>>($"{rawData}");
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"AnagStatiComm Read from REDIS: {ts.TotalMilliseconds}ms");
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.AnagStatiComm());
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(Utils.redisStatoCom, rawData, getRandTOut(redisLongTimeCache));
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"AnagStatiComm Read from DB: {ts.TotalMilliseconds}ms");
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<ListValuesModel>();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce l'anagrafica STATI per intero
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<List<AnagStatiModel>> AnagStatiGetAllAsync()
|
|
{
|
|
List<AnagStatiModel> dbResult = new List<AnagStatiModel>();
|
|
// cerco in redis...
|
|
var currKey = Utils.redisAnagStati;
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
dbResult = JsonConvert.DeserializeObject<List<AnagStatiModel>>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
dbResult = await IocDbController.AnagStatiGetAllAsync();
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(dbResult);
|
|
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
return dbResult;
|
|
}
|
|
|
|
public async Task<List<ListValuesModel>> AnagTipoArtLV()
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string source = "DB";
|
|
List<ListValuesModel>? result = new List<ListValuesModel>();
|
|
// cerco in redis...
|
|
RedisValue rawData = await redisDb.StringGetAsync(Utils.redisTipoArt);
|
|
if (!string.IsNullOrEmpty($"{rawData}"))
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<ListValuesModel>>($"{rawData}");
|
|
source = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.AnagTipoArtLV());
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(Utils.redisTipoArt, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"AnagTipoArtLV Read from {source}: {ts.TotalMilliseconds}ms");
|
|
if (result == null)
|
|
{
|
|
result = new List<ListValuesModel>();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco Codice articolo con dati dossier gestiti
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<List<string>> ArticleWithDossier()
|
|
{
|
|
List<string>? result = new List<string>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = Utils.redisArtByDossier;
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<string>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.ArticleWithDossier());
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<string>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"ArticleWithDossier | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Eliminazione record selezionato
|
|
/// </summary>
|
|
/// <param name="currRec"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> ArticoliDeleteRecord(AnagArticoliModel currRec)
|
|
{
|
|
bool fatto = await SpecDbController.ArticoliDeleteRecord(currRec);
|
|
await resetCacheArticoli();
|
|
return fatto;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco ultimi articoli data amcchina
|
|
/// </summary>
|
|
/// <param name="idxMacc"></param>
|
|
/// <returns></returns>
|
|
public async Task<List<AnagArticoliModel>> ArticoliGetLastByMaccAsync(string idxMacc)
|
|
{
|
|
List<AnagArticoliModel>? result = new List<AnagArticoliModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisArtList}:Last:{idxMacc}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<AnagArticoliModel>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.ArticoliGetLastByMaccAsync(idxMacc);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<AnagArticoliModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"ArticoliGetLastByMaccAsync | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco articoli cercati
|
|
/// </summary>
|
|
/// <param name="numRecord"></param>
|
|
/// <param name="searchVal"></param>
|
|
/// <returns></returns>
|
|
public async Task<List<AnagArticoliModel>> ArticoliGetSearch(int numRecord, string azienda, string searchVal)
|
|
{
|
|
List<AnagArticoliModel>? result = new List<AnagArticoliModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string sKey = string.IsNullOrEmpty(searchVal) ? "***" : searchVal;
|
|
string currKey = $"{Utils.redisArtList}:{azienda}:{sKey}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<AnagArticoliModel>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.ArticoliGetSearch(numRecord, azienda, searchVal));
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache / 5));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<AnagArticoliModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"ArticoliGetSearch | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aggiornamento record selezionato
|
|
/// </summary>
|
|
/// <param name="currRec"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> ArticoliUpdateRecord(AnagArticoliModel currRec)
|
|
{
|
|
bool fatto = await SpecDbController.ArticoliUpdateRecord(currRec);
|
|
await resetCacheArticoli();
|
|
return fatto;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica se sia possiubile cancellare articolo dato suo CodArt cercando su redis o su
|
|
/// tab veto da DB
|
|
/// </summary>
|
|
/// <param name="CodArt"></param>
|
|
/// <returns></returns>
|
|
public bool ArticoloDelEnabled(object CodArt)
|
|
{
|
|
bool answ = false;
|
|
string codArticolo = $"{CodArt}";
|
|
int cacheCheckArtUsato = 1;
|
|
int.TryParse(_configuration.GetValue<string>("ServerConf:cacheCheckArtUsato"), out cacheCheckArtUsato);
|
|
TimeSpan TTLCache = getRandTOut(cacheCheckArtUsato);
|
|
// cerco in cache redis...
|
|
string redKeyArtUsed = $"{Utils.redKeyArtUsed}:{codArticolo}";
|
|
string redKeyTabCheckArt = Utils.redKeyTabCheckArt;
|
|
var rawData = redisDb.StringGet(redKeyArtUsed);
|
|
if (!string.IsNullOrEmpty(rawData))
|
|
{
|
|
bool.TryParse(rawData, out answ);
|
|
}
|
|
else
|
|
{
|
|
// controllo non sia stato mai prodotto sennò non posso cancellare...
|
|
try
|
|
{
|
|
// cerco in cache se ci sia la tabella con gli articoli impiegati...
|
|
var rawTable = redisDb.StringGet(redKeyTabCheckArt);
|
|
List<string>? artList = new List<string>();
|
|
if (!string.IsNullOrEmpty(rawTable))
|
|
{
|
|
artList = JsonConvert.DeserializeObject<List<string>>($"{rawTable}");
|
|
}
|
|
// rileggo...
|
|
if (artList == null || artList.Count == 0)
|
|
{
|
|
artList = new List<string>();
|
|
var tabArticoli = SpecDbController.ArticoliGetUsed();
|
|
var codList = tabArticoli.Select(x => x.CodArticolo);
|
|
foreach (string cod in codList)
|
|
{
|
|
artList.Add(cod);
|
|
}
|
|
// SE fosse vuoto aggiungo comunque il cado "ND"...
|
|
if (artList.Count == 0)
|
|
{
|
|
artList.Add("ND");
|
|
}
|
|
// salvo
|
|
rawTable = JsonConvert.SerializeObject(artList);
|
|
redisDb.StringSet(redKeyTabCheckArt, rawTable, TTLCache);
|
|
}
|
|
// cerco nella tabella: se ci fosse --> disabilitato delete
|
|
bool usato = false;
|
|
if (artList != null && artList.Count > 0)
|
|
{
|
|
usato = artList.Contains(codArticolo);
|
|
}
|
|
answ = !usato;
|
|
redisDb.StringSet(redKeyArtUsed, $"{answ}", TTLCache);
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua split ODL
|
|
/// </summary>
|
|
/// <param name="idxMacchina">macchina</param>
|
|
/// <param name="doConfirm">effettuare conferma qty</param>
|
|
/// <param name="qtyFromLast">imposta la qty prox ODL da ODL che si chiude</param>
|
|
/// <param name="matrOpr">matricola operatore</param>
|
|
/// <param name="roundStep">Round Step quantità prox ODL (corrente come riferimento)</param>
|
|
/// <param name="keyRichiesta">Cod ext da associare all'ODL</param>
|
|
/// <returns></returns>
|
|
public async Task<string> AutoStartOdlAsync(string idxMacchina, bool doConfirm, bool qtyFromLast, int matrOpr, int roundStep = 100, string keyRichiesta = "")
|
|
{
|
|
string answ = "KO";
|
|
DateTime adesso = DateTime.Now;
|
|
|
|
// verifico NON CI SIA un veto a NUOVI split...
|
|
string redKey = $"{Utils.redisVetoSplitOdl}:{idxMacchina}";
|
|
var rawData = await redisDb.StringGetAsync(redKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
Log.Info($"VETO ATTIVO | Richiesto forceSplitOdl per impianto {idxMacchina} | impossibile procedere");
|
|
}
|
|
else
|
|
{
|
|
// registro VETO x altri split... 5 minuti
|
|
await redisDb.StringSetAsync(redKey, $"Inizio SPLIT-ODL {adesso}", TimeSpan.FromMinutes(5));
|
|
// setup dati da config
|
|
bool confRett = false;
|
|
int modoConfProd = -1;
|
|
bool slaveConfirmPzProd = false;
|
|
var configData = await ConfigGetAllAsync();
|
|
if (configData != null)
|
|
{
|
|
var currRec = configData.FirstOrDefault(x => x.Chiave == "confRett");
|
|
if (currRec != null)
|
|
{
|
|
bool.TryParse(currRec.Valore, out confRett);
|
|
}
|
|
currRec = configData.FirstOrDefault(x => x.Chiave == "modoConfProd");
|
|
if (currRec != null)
|
|
{
|
|
int.TryParse(currRec.Valore, out modoConfProd);
|
|
}
|
|
currRec = configData.FirstOrDefault(x => x.Chiave == "SlaveConfirmPzProd");
|
|
if (currRec != null)
|
|
{
|
|
bool.TryParse(currRec.Valore, out slaveConfirmPzProd);
|
|
}
|
|
}
|
|
// calcolo la qta da gestire
|
|
int qtyConf = 0;
|
|
int qtyNew = 0;
|
|
int qtyScarto = 0;
|
|
if (doConfirm)
|
|
{
|
|
try
|
|
{
|
|
var rigaProd = await IocDbController.PezziProdMacchinaAsync(idxMacchina);
|
|
var statoProd = await IocDbController.StatoProdMacchinaAsync(idxMacchina, adesso);
|
|
qtyConf = rigaProd.pezziNonConfermati;
|
|
qtyScarto = statoProd.Pz2RecScarto;
|
|
// calcolo nuovi pezzi da confermare
|
|
if (qtyFromLast)
|
|
{
|
|
roundStep = roundStep == 0 ? 1 : roundStep;
|
|
double ratio = (double)qtyConf / roundStep;
|
|
qtyNew = (int)Math.Round(Math.Ceiling(ratio) * roundStep, 0);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"AutoStartOdlAsync | Errore recupero pezzi da confermare | idxMacchina {idxMacchina}{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
|
|
// chiamo metodo redis/db...
|
|
try
|
|
{
|
|
// recupero ODL corrente
|
|
var currData = await IocDbController.OdlCurrByMaccAsync(idxMacchina);
|
|
if (currData != null && currData.IdxOdl > 0)
|
|
{
|
|
// preparo var x master/slave
|
|
bool isMachMaster = await IobIsMasterAsync(idxMacchina);
|
|
List<Macchine2SlaveModel> slaveList = new();
|
|
if (isMachMaster)
|
|
{
|
|
List<Macchine2SlaveModel> allSlaveList = await IocDbController.Macchine2SlaveAsync();
|
|
slaveList = allSlaveList.Where(x => x.IdxMacchina == idxMacchina).ToList();
|
|
}
|
|
|
|
// registro un evento di inizio attrezzaggio (idxTipoEv = 2)
|
|
int idxEvento = 2;
|
|
Log.Info($"Invio evento ODL-SPLIT per macchina {idxMacchina} | ev: {idxEvento} | art: {currData.CodArticolo} | qty conf: {qtyConf} | sty sca: {qtyScarto} | new qty: {qtyNew}");
|
|
|
|
// creo evento
|
|
EventListModel newRecEv = new EventListModel()
|
|
{
|
|
CodArticolo = currData.CodArticolo,
|
|
IdxMacchina = idxMacchina,
|
|
IdxTipo = idxEvento,
|
|
InizioStato = adesso,
|
|
MatrOpr = matrOpr,
|
|
pallet = "",
|
|
Value = "ODL-SPLIT"
|
|
};
|
|
inputComandoMapo resCmd = await scriviRigaEventoBarcodeAsync(newRecEv);
|
|
|
|
// era 100, messo 50...
|
|
int wTime = 50;
|
|
|
|
// eventuale conferma produzione
|
|
if (doConfirm)
|
|
{
|
|
await Task.Delay(wTime);
|
|
adesso = DateTime.Now;
|
|
// chiamo conferma produzione...
|
|
try
|
|
{
|
|
string chiamata = confRett ? "confermaProdMacchinaFull" : "confermaProdMacchina";
|
|
Log.Info($"Chiamata a {chiamata} con parametri {currData.IdxMacchina} |{matrOpr} | {DateTime.Now.AddDays(-10)} | {DateTime.Now} | {qtyConf} | 0 | {qtyScarto} | {DateTime.Now} | false");
|
|
string idxMacchinaSel = currData.IdxMacchina;
|
|
bool fatto = false;
|
|
if (confRett)
|
|
{
|
|
// confermo al netto dei pezzi lasciati...
|
|
fatto = await IocDbController.ConfermaProdMacchinaFullAsync(idxMacchinaSel, modoConfProd, qtyConf, 0, qtyScarto, adesso, matrOpr);
|
|
if (slaveConfirmPzProd)
|
|
{
|
|
foreach (var machine in slaveList)
|
|
{
|
|
await IocDbController.ConfermaProdMacchinaFullAsync(machine.IdxMacchinaSlave, modoConfProd, qtyConf, 0, qtyScarto, adesso, matrOpr);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fatto = await IocDbController.ConfermaProdMacchinaAsync(idxMacchinaSel, modoConfProd, qtyConf, qtyScarto, adesso, matrOpr);
|
|
if (slaveConfirmPzProd)
|
|
{
|
|
foreach (var machine in slaveList)
|
|
{
|
|
await IocDbController.ConfermaProdMacchinaAsync(idxMacchinaSel, modoConfProd, qtyConf, qtyScarto, adesso, matrOpr);
|
|
}
|
|
}
|
|
}
|
|
if (!fatto)
|
|
{
|
|
Log.Error($"ERRORE in chiamata {chiamata}");
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in ConfermaProduzione{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
// 2025.02.19 portato da 100 a 1000 ms attesa x evitare che ODL sia avviato PRIMA della conferma
|
|
// attendo 1000 msec x chiudere ODL
|
|
await Task.Delay(1000);
|
|
// chiamo splitOdl
|
|
await IocDbController.AutoStartOdlAsync(currData.IdxOdl, 0, idxMacchina, currData.TCRichAttr, currData.PzPallet, $"Nuovo ODL da forceSplitOdl.autoStart", true, qtyNew, keyRichiesta);
|
|
|
|
// elimino eventuale ODL precedente...
|
|
string currKey = $"{Utils.redisOdlCurrByMac}:{idxMacchina}";
|
|
await redisDb.KeyDeleteAsync(currKey);
|
|
|
|
// ricalcola ODL macchina
|
|
var newOdl = await GetCurrOdlAsync(idxMacchina);
|
|
// attendo 1000 msec
|
|
await Task.Delay(1000);
|
|
|
|
adesso = DateTime.Now;
|
|
// registro fine ODL (idxTipoEv = 1)
|
|
idxEvento = 1;
|
|
Log.Info($"Invio evento FINE ODL-SPLIT | idx: {idxMacchina} | ev: {idxEvento} | art: {currData.CodArticolo}");
|
|
// costruisco nuovo evento
|
|
newRecEv = new EventListModel()
|
|
{
|
|
CodArticolo = currData.CodArticolo,
|
|
IdxMacchina = idxMacchina,
|
|
IdxTipo = idxEvento,
|
|
InizioStato = adesso,
|
|
MatrOpr = matrOpr,
|
|
pallet = "",
|
|
Value = "ODL-START"
|
|
};
|
|
resCmd = await scriviRigaEventoBarcodeAsync(newRecEv);
|
|
// invio eventi setup a macchina....
|
|
string setArtVal = $"{currData.CodArticolo}";
|
|
string setPzCommVal = $"{qtyNew}";
|
|
string setCommVal = $"ODL{newOdl}";
|
|
if (!string.IsNullOrEmpty(keyRichiesta))
|
|
{
|
|
setCommVal = $"{keyRichiesta} ODL{newOdl}";
|
|
}
|
|
try
|
|
{
|
|
// invio task caricamento dati ODL
|
|
Dictionary<taskType, string> updDict = new Dictionary<taskType, string>();
|
|
updDict.Add(taskType.setArt, setArtVal);
|
|
updDict.Add(taskType.setComm, setCommVal);
|
|
updDict.Add(taskType.setPzComm, setPzCommVal);
|
|
#if false
|
|
addTask4Machine(idxMacchina, taskType.setArt, setArtVal);
|
|
addTask4Machine(idxMacchina, taskType.setComm, setCommVal);
|
|
addTask4Machine(idxMacchina, taskType.setPzComm, setPzCommVal);
|
|
|
|
updateMachineParameter(idxMacchina, "setArt", setArtVal);
|
|
updateMachineParameter(idxMacchina, "setComm", setCommVal);
|
|
updateMachineParameter(idxMacchina, "setPzComm", setPzCommVal);
|
|
#endif
|
|
// recupero set attuale parametri
|
|
var currMachPar = await MachineParamListAsync(idxMacchina);
|
|
List<ObjItemDTO> list2upd = new();
|
|
// aggiorno i valori interessati tra quelli nel dizionario
|
|
foreach (var item in updDict)
|
|
{
|
|
var cRec = currMachPar.FirstOrDefault(x => x.uid == $"{item.Key}");
|
|
if (cRec != null)
|
|
{
|
|
list2upd.Add(cRec);
|
|
}
|
|
}
|
|
// aggiungo task di setParameters x la commessa...
|
|
updDict.Add(taskType.setParameter, setCommVal);
|
|
// salvo
|
|
await AddTask4MacListAsync(idxMacchina, updDict);
|
|
await MachineParamUpsertAsync(idxMacchina, list2upd);
|
|
}
|
|
catch
|
|
{ }
|
|
// chiamo refresh MSE
|
|
await IocDbController.RecalcMseAsync(idxMacchina, 0);
|
|
// resetto stato macchina...
|
|
var kStatoMacc = $"{Utils.redisStatoMacch}:{idxMacchina}";
|
|
await redisDb.KeyDeleteAsync(kStatoMacc);
|
|
answ = "OK";
|
|
Log.Info($"Effettuato reset e ricalcoli x split ODL per macchina {idxMacchina}");
|
|
// se è una master richiamo fix x child...
|
|
if (isMachMaster)
|
|
{
|
|
Dictionary<taskType, string> updDict = new Dictionary<taskType, string>();
|
|
string ts = "";
|
|
string outData = "";
|
|
await IocDbController.OdlFixMachineSlaveAsync(idxMacchina, 30, 1);
|
|
foreach (var machine in slaveList)
|
|
{
|
|
// invio chiusura attrezzaggio
|
|
ts = string.Format("{0:yyMMdd}T{0:HHmmss.fff}Z", DateTime.Now);
|
|
outData = $"TS:{ts}|MATR:{matrOpr}|ODL:{newOdl}";
|
|
|
|
updDict.Clear();
|
|
updDict.Add(taskType.setArt, setArtVal);
|
|
updDict.Add(taskType.setComm, setCommVal);
|
|
updDict.Add(taskType.setPzComm, setPzCommVal);
|
|
|
|
#if false
|
|
addTask4Machine(machine.IdxMacchinaSlave, taskType.fixStopSetup, outData);
|
|
addTask4Machine(machine.IdxMacchinaSlave, taskType.forceResetPzCount, outData);
|
|
// invio task caricamento dati ODL
|
|
addTask4Machine(machine.IdxMacchinaSlave, taskType.setArt, setArtVal);
|
|
addTask4Machine(machine.IdxMacchinaSlave, taskType.setComm, setCommVal);
|
|
addTask4Machine(machine.IdxMacchinaSlave, taskType.setPzComm, setPzCommVal);
|
|
|
|
updateMachineParameter(machine.IdxMacchinaSlave, "setArt", setArtVal);
|
|
updateMachineParameter(machine.IdxMacchinaSlave, "setComm", setCommVal);
|
|
updateMachineParameter(machine.IdxMacchinaSlave, "setPzComm", setPzCommVal);
|
|
#endif
|
|
|
|
// recupero set attuale parametri
|
|
var currMachPar = await MachineParamListAsync(machine.IdxMacchinaSlave);
|
|
List<ObjItemDTO> list2upd = new();
|
|
// aggiorno i valori interessati tra quelli nel dizionario
|
|
foreach (var item in updDict)
|
|
{
|
|
var cRec = currMachPar.FirstOrDefault(x => x.uid == $"{item.Key}");
|
|
if (cRec != null)
|
|
{
|
|
list2upd.Add(cRec);
|
|
}
|
|
}
|
|
// aggiungo task di setParameters x la commessa...
|
|
updDict.Add(taskType.fixStopSetup, outData);
|
|
updDict.Add(taskType.forceResetPzCount, outData);
|
|
updDict.Add(taskType.setParameter, setCommVal);
|
|
// salvo
|
|
await AddTask4MacListAsync(machine.IdxMacchinaSlave, updDict);
|
|
await MachineParamUpsertAsync(machine.IdxMacchinaSlave, list2upd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
public string CalcRecipe(RecipeModel currRecipe)
|
|
{
|
|
return mongoController.CalcRecipe(currRecipe);
|
|
}
|
|
|
|
/// <summary>
|
|
/// controlla se da il segnale di "microstato" deriva un evento da generare - modalità OFFLINE
|
|
/// </summary>
|
|
/// <param name="idxMacchina">idx macchina</param>
|
|
/// <param name="valore">valOut ingresso</param>
|
|
/// <param name="dtEve">data-ora evento (server)</param>
|
|
/// <param name="contatore">sequenza dati inviati</param>
|
|
/// <param name="datiMaccCache">dati macchina in cache (opzionale, se null fa lookup)</param>
|
|
/// <returns></returns>
|
|
public async Task<inputComandoMapo> CheckMicroStatoAsync(string idxMacchina, string valore, DateTime dtEve, string contatore, Dictionary<string, string>? datiMaccCache = null)
|
|
{
|
|
// recupero SE IMPIEGATO REDIS i valori del Dictionary della macchina...
|
|
Dictionary<string, string> datiMacc = datiMaccCache ?? await mDatiMacchineAsync(idxMacchina);
|
|
|
|
// processing
|
|
inputComandoMapo answ = new inputComandoMapo();
|
|
|
|
// SE no trovassi verifico se esista la macchina altrimenti la creo... REDIS compliant
|
|
if (!datiMacc.ContainsKey(idxMacchina))
|
|
{
|
|
await verificaIdxMacchinaAsync(idxMacchina);
|
|
}
|
|
|
|
// continuo processing...
|
|
string CodArticolo = datiMacc["CodArticolo"];
|
|
if (string.IsNullOrEmpty(CodArticolo))
|
|
{
|
|
var allDatiMacch = await IocDbController.DatiMacchineGetAllAsync();
|
|
var recMacc = allDatiMacch.FirstOrDefault(x => x.IdxMacchina == idxMacchina);
|
|
if (recMacc != null)
|
|
{
|
|
CodArticolo = recMacc.CodArticoloA;
|
|
}
|
|
}
|
|
// preparo gestione val ingresso
|
|
int? valINT = 0;
|
|
int idxTipoEv = 0;
|
|
int next_idxMS = 0;
|
|
try
|
|
{
|
|
valINT = int.Parse(valore, NumberStyles.HexNumber);
|
|
int idxFamIn = Convert.ToInt32(datiMacc["IdxFamIn"]);
|
|
int idxMicroStato = Convert.ToInt32(datiMacc["IdxMicroStato"]);
|
|
int valIOB = Convert.ToInt32(valINT);
|
|
next_idxMS = idxMicroStato;
|
|
// recupero singolo valOut (stringa) x chiave
|
|
string todoSMI = await ValoreSmiAsync(idxFamIn, idxMicroStato, valIOB);
|
|
// solo se ho trovato un risultato nella tab SMI della famiglia macchina...
|
|
if (!string.IsNullOrEmpty(todoSMI) && todoSMI.Contains("_"))
|
|
{
|
|
// splitto e salvo valori OUT...
|
|
string[] valori = todoSMI.Split('_');
|
|
idxTipoEv = Convert.ToInt32(valori[0]);
|
|
next_idxMS = Convert.ToInt32(valori[1]);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"[ChkMiSt_5a] - - Eccezione in recupero riga Trans ingressi | idxMacchina {idxMacchina} | valINT {valINT}:{Environment.NewLine}{exc}", Environment.NewLine, exc, valINT, idxMacchina);
|
|
}
|
|
|
|
// effettuo update vari SU DB!!!
|
|
MicroStatoMacchinaModel newRecMsm = new MicroStatoMacchinaModel()
|
|
{
|
|
IdxMacchina = idxMacchina,
|
|
IdxMicroStato = next_idxMS,
|
|
InizioStato = dtEve,
|
|
Value = valore
|
|
};
|
|
if (idxTipoEv > 0)
|
|
{
|
|
// preparo record
|
|
string valEsteso = string.Format("[{0}] {1}", contatore.PadLeft(3, '0'), valore);
|
|
// creo evento
|
|
EventListModel newRecEv = new EventListModel()
|
|
{
|
|
CodArticolo = CodArticolo,
|
|
IdxMacchina = idxMacchina,
|
|
IdxTipo = idxTipoEv,
|
|
InizioStato = dtEve,
|
|
MatrOpr = 0,
|
|
pallet = "-",
|
|
Value = valEsteso
|
|
};
|
|
// salva e processa evento + microstato
|
|
answ = await scriviRigaEventoAsync(newRecMsm, newRecEv);
|
|
}
|
|
else
|
|
{
|
|
if (useFactory)
|
|
{
|
|
await using var scope = _scopeFactory.CreateAsyncScope();
|
|
var iocService = scope.ServiceProvider.GetRequiredService<IIocService>();
|
|
// solo microstato
|
|
await iocService.MicroStatoMacchinaUpsertAsync(newRecMsm);
|
|
}
|
|
else
|
|
{
|
|
// solo microstato
|
|
await IocDbController.MicroStatoMacchinaUpsertAsync(newRecMsm);
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
public async Task<List<ConfigModel>> ConfigGetAllAsync()
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
List<ConfigModel>? result = new List<ConfigModel>();
|
|
// cerco in redis...
|
|
RedisValue rawData = await redisDb.StringGetAsync(Utils.redisConfKey);
|
|
if (!string.IsNullOrEmpty($"{rawData}"))
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<ConfigModel>>($"{rawData}");
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"ConfigGetAllAsync Read from REDIS: {ts.TotalMilliseconds}ms");
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.ConfigGetAllAsync();
|
|
//result = await Task.FromResult(SpecDbController.ConfigGetAllAsync());
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(Utils.redisConfKey, rawData, getRandTOut(redisLongTimeCache));
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"ConfigGetAllAsync Read from DB: {ts.TotalMilliseconds}ms");
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<ConfigModel>();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset dati cache config
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task ConfigResetCache()
|
|
{
|
|
await redisDb.StringSetAsync(Utils.redisConfKey, "");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update chiave config
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<bool> ConfigUpdate(ConfigModel updRec)
|
|
{
|
|
return await Task.FromResult(SpecDbController.ConfigUpdate(updRec));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco completo valori DatiMacchine
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<List<DatiMacchineModel>> DatiMacchineGetAll()
|
|
{
|
|
List<DatiMacchineModel>? result = new List<DatiMacchineModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisBaseAddr}:TabDatiMacchine:ALL";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<DatiMacchineModel>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.DatiMacchineGetAll());
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<DatiMacchineModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"DatiMacchineGetAll | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
public async Task<List<DecNumArticoliModel>> DecNumArtGetFiltAsync(string codArt = "")
|
|
{
|
|
List<DecNumArticoliModel> result = new();
|
|
string tag = string.IsNullOrEmpty(codArt) ? "ALL" : codArt;
|
|
string currKey = $"{Utils.redisDecNumArtKey}:{tag}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<DecNumArticoliModel>>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.DecNumArtGetFiltAsync(codArt);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose del connettore ai dati
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
// Clear database controller
|
|
SpecDbController.Dispose();
|
|
mongoController.Dispose();
|
|
redisConn.Dispose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce l'elenco delle date dei dossier x una macchina (se presenti) Impiegata anche
|
|
/// cache redis
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<List<DossierModel>> DossierLastByMachAsync(string idxMacchina)
|
|
{
|
|
List<DossierModel> result = new List<DossierModel>();
|
|
|
|
var currKey = $"{Utils.redisDossByMacLast}:{idxMacchina}";
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<DossierModel>>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.DossGetLastByMaccAsync(idxMacchina);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<DossierModel>();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Eliminazione di un dossier
|
|
/// </summary>
|
|
/// <param name="selRecord">record dossier da eliminare</param>
|
|
/// <returns></returns>
|
|
public async Task<bool> DossiersDeleteRecord(DossierModel selRecord)
|
|
{
|
|
bool result = false;
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
result = await SpecDbController.DossiersDeleteRecord(selRecord);
|
|
// elimino cache redis...
|
|
RedisValue pattern = new RedisValue($"{Utils.redisDossByMac}:*");
|
|
bool answ = await RedisFlushPatternAsync(pattern);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"DossiersDeleteRecord | IdxMacchina {selRecord.IdxMacchina} | DtRif {selRecord.DtRif} | IdxODL {selRecord.IdxODL} | {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco ultimi n record DOssiers (che contengono ad esempio "salvataggi" di FLuxLog) dato
|
|
/// macchina (ordinato x data registrazione)
|
|
/// </summary>
|
|
/// <param name="IdxMacchina">* = tutte, altrimenti solo x una data macchina</param>
|
|
/// <param name="DtStart">Data minima per estrazione records</param>
|
|
/// <param name="DtEnd">Data Massima per estrazione records</param>
|
|
/// <param name="MaxRec">Num Max records da recuperare</param>
|
|
/// <returns></returns>
|
|
public async Task<List<DossierModel>> DossiersGetLastFilt(string IdxMacchina, string CodArticolo, DateTime DtStart, DateTime DtEnd, int MaxRec)
|
|
{
|
|
List<DossierModel>? result = new List<DossierModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisDossByMac}:{IdxMacchina}:{CodArticolo}:{DtStart:yyyyMMddHHmm}:{DtEnd:yyyyMMddHHmm}:{MaxRec}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<DossierModel>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await SpecDbController.DossiersGetLastFiltAsync(IdxMacchina, CodArticolo, DtStart, DtEnd, MaxRec);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache / 5));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<DossierModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"DossiersGetLastFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Inserimento nuovo record dossier
|
|
/// </summary>
|
|
/// <param name="currDoss"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> DossiersInsert(DossierModel currDoss)
|
|
{
|
|
// aggiorno record sul DB
|
|
bool answ = await SpecDbController.DossiersInsert(currDoss);
|
|
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua salvataggio snapshot parametri (con stored) + svuota eventuale cache redis
|
|
/// </summary>
|
|
/// <param name="IdxMacchina">macchina</param>
|
|
/// <param name="MaxSec">NUm massimo secondi per recuperare dati correnti</param>
|
|
/// <param name="DtRif">DataOra riferimento x cui prendere valori antecedenti</param>
|
|
/// <returns></returns>
|
|
public async Task<bool> DossiersTakeParamsSnapshotLast(string IdxMacchina, DateTime dtMin, DateTime dtMax)
|
|
{
|
|
bool answ = false;
|
|
await Task.Delay(1);
|
|
Log.Info($"Richiesta snapshot per macchina {IdxMacchina} | periodo {dtMin} --> {dtMax}");
|
|
// chiamo stored x salvare parametri
|
|
SpecDbController.DossiersTakeParamsSnapshotLast(IdxMacchina, dtMin, dtMax);
|
|
// elimino cache redis...
|
|
RedisValue pattern = new RedisValue($"{Utils.redisDossByMac}:*");
|
|
answ = await RedisFlushPatternAsync(pattern);
|
|
Log.Info($"Svuotata cache dossier | {pattern}");
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update valOut dossier
|
|
/// </summary>
|
|
/// <param name="currDoss"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> DossiersUpdateValore(DossierModel currDoss)
|
|
{
|
|
// aggiorno record sul DB
|
|
bool answ = await SpecDbController.DossiersUpdateValore(currDoss);
|
|
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco aziende
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public Task<List<AnagGruppiModel>> ElencoAziende()
|
|
{
|
|
return Task.FromResult(SpecDbController.AnagGruppiAziende());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco fasi
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public Task<List<AnagGruppiModel>> ElencoGruppiFase()
|
|
{
|
|
List<AnagGruppiModel> result = new List<AnagGruppiModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisAnagGruppi}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
var rawResult = JsonConvert.DeserializeObject<List<AnagGruppiModel>>($"{rawData}");
|
|
if (rawResult != null)
|
|
{
|
|
result = rawResult;
|
|
}
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = SpecDbController.AnagGruppiFase();
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache / 5));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<AnagGruppiModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"ElencoGruppiFase | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return Task.FromResult(result);
|
|
}
|
|
|
|
public Task<List<LinkMenuModel>> ElencoLink()
|
|
{
|
|
return Task.FromResult(SpecDbController.ElencoLink());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aggiunta record EventList
|
|
/// </summary>
|
|
/// <param name="newRec"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> EvListInsert(EventListModel newRec)
|
|
{
|
|
return await SpecDbController.EvListInsert(newRec);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Imposta in redis la scadenza della pagina x il reload
|
|
/// </summary>
|
|
/// <param name="expTime"></param>
|
|
/// <returns></returns>
|
|
public DateTime ExpiryReloadParamGet()
|
|
{
|
|
DateTime dtRif = DateTime.Now;
|
|
string currKey = $"{Utils.redisParamPageExp}";
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
dtRif = JsonConvert.DeserializeObject<DateTime>($"{rawData}");
|
|
}
|
|
return dtRif;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Imposta in redis la scadenza della pagina x il reload
|
|
/// </summary>
|
|
/// <param name="expTime"></param>
|
|
/// <returns></returns>
|
|
public bool ExpiryReloadParamSet(DateTime expTime)
|
|
{
|
|
bool fatto = false;
|
|
string currKey = $"{Utils.redisParamPageExp}";
|
|
string rawData = JsonConvert.SerializeObject(expTime);
|
|
fatto = redisDb.StringSet(currKey, rawData);
|
|
return fatto;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Task completo sistemazione dossier quotidiani mancanti
|
|
/// </summary>
|
|
/// <param name="idxMacc"></param>
|
|
/// <returns></returns>
|
|
public async Task<string> FixDailyDossierAsync(string idxMacc)
|
|
{
|
|
string answ = "";
|
|
// verifico se si possa processare, ovvero tab ConfFlux x macchina sia valorizzata...
|
|
var confDataMach = await ConfFluxMach(idxMacc);
|
|
if (confDataMach.Count > 0)
|
|
{
|
|
// determino ultima data da processare (inizio oggi, a mezzanotte)
|
|
DateTime dtTo = DateTime.Today;
|
|
DateTime dtFrom = dtTo;
|
|
// determino data di partenza, prima da dossier esistenti
|
|
var listaDoss = await DossierLastByMachAsync(idxMacc);
|
|
if (listaDoss.Count > 0)
|
|
{
|
|
// primo giorno DOPO ultima registrazione
|
|
dtFrom = listaDoss
|
|
.Select(x => x.DtRif)
|
|
.OrderByDescending(x => x)
|
|
.FirstOrDefault()
|
|
.AddDays(1);
|
|
}
|
|
else
|
|
{
|
|
// ...o da fluxLog acquisiti...
|
|
var listaFL = await FluxLogFirstByMachAsync(idxMacc);
|
|
if (listaFL.Count > 0)
|
|
{
|
|
// giorno successivo a prima registrazione
|
|
dtFrom = listaFL
|
|
.OrderBy(x => x)
|
|
.FirstOrDefault()
|
|
.AddDays(1);
|
|
}
|
|
}
|
|
string caller = $"takeFlogSnapshot({idxMacc})";
|
|
DateTime dtStart = dtFrom.Date;
|
|
DateTime dtEnd = dtFrom;
|
|
// max 10 dossier alla volta (se non configurato diversamente)
|
|
int maxAdd = 1;
|
|
string confVal = await tryGetConfigAsync("IO_numDossMaxCreate");
|
|
if (!string.IsNullOrEmpty(confVal))
|
|
{
|
|
int.TryParse(confVal, out maxAdd);
|
|
}
|
|
|
|
if (dtStart < dtTo)
|
|
{
|
|
// verifico di avere almeno 1 dossier da produrre ciclo fino ad esaurire le
|
|
// date da processare
|
|
while (dtStart < dtTo && maxAdd > 0)
|
|
{
|
|
// sistemo end
|
|
dtEnd = dtStart.AddDays(1);
|
|
// effettuo chiamata registrazione snapshot!
|
|
answ = await FluxLogSaveSnapshotAsync(idxMacc, dtStart, dtEnd, caller);
|
|
// incremento START...
|
|
dtStart = dtEnd;
|
|
// riduco il numero di chiamate ammesse x singolo task
|
|
maxAdd--;
|
|
}
|
|
// reset cache dossier...
|
|
await DossierLastByMachResetAsync(idxMacc);
|
|
answ = "OK";
|
|
}
|
|
else
|
|
{
|
|
Log.Warn("FixDailyDossierAsync | NO more to add");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log.Warn("FixDailyDossierAsync | NO ConfFluxData");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
public async Task<bool> FlushRedisCache()
|
|
{
|
|
await Task.Delay(1);
|
|
RedisValue pattern = Utils.RedValue("*");
|
|
bool answ = await RedisFlushPatternAsync(pattern);
|
|
// rileggo vocabolario.,..
|
|
ObjVocabolario = VocabolarioGetAll();
|
|
return answ;
|
|
}
|
|
|
|
public async Task<bool> FlushRedisKey(string redKey)
|
|
{
|
|
await Task.Delay(1);
|
|
RedisValue pattern = Utils.RedValue(redKey);
|
|
bool answ = await RedisFlushPatternAsync(pattern);
|
|
return answ;
|
|
}
|
|
|
|
public List<FluxLogDTO> FluxLogDtoGetByFlux(string Valore)
|
|
{
|
|
List<FluxLogDTO> answ = new List<FluxLogDTO>();
|
|
DossierFluxLogDTO? result = JsonConvert.DeserializeObject<DossierFluxLogDTO>(Valore);
|
|
if (result != null)
|
|
{
|
|
if (result.ODL != null)
|
|
{
|
|
answ = result
|
|
.ODL
|
|
.OrderBy(x => x.CodFlux)
|
|
.ToList();
|
|
// inizializzo SE necessario
|
|
foreach (var item in answ)
|
|
{
|
|
item.ValoreEdit = String.IsNullOrEmpty(item.ValoreEdit) ? item.Valore : item.ValoreEdit;
|
|
}
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco ultimi n record flux log dato macchina e flusso (ordinato x data registrazione)
|
|
/// </summary>
|
|
/// <param name="DtMax">Data massima x eventi</param>
|
|
/// <param name="DtMin">Data minima x eventi</param>
|
|
/// <param name="IdxMacchina">* = tutte, altrimenti solo x una data macchina</param>
|
|
/// <param name="CodFlux">*=tutti, altrimenti solo selezionato</param>
|
|
/// <param name="MaxRec">numero massimo record da restituire</param>
|
|
/// <returns></returns>
|
|
public async Task<List<FluxLogModel>> FluxLogGetLastFilt(DateTime DtMax, DateTime DtMin, string IdxMacchina, string CodFlux, int MaxRec, double redisCacheSec)
|
|
{
|
|
List<FluxLogModel>? result = new List<FluxLogModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisFluxLogFilt}:{IdxMacchina}:{CodFlux}:{MaxRec}:{DtMax:yyyyMMddHHmm}:{DtMin:yyyyMMddHHmm}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<FluxLogModel>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.FluxLogGetLastFilt(DtMax, DtMin, IdxMacchina, CodFlux, MaxRec));
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
if (string.IsNullOrEmpty(canCacheParametri))
|
|
{
|
|
canCacheParametri = await tryGetConfigAsync("SPEC_ParametriEnableRedisCache");
|
|
}
|
|
if (canCacheParametri != "false")
|
|
{
|
|
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisCacheSec));
|
|
}
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<FluxLogModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"FluxLogGetLastFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il valOut dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza
|
|
/// ODL NO invio/gestione ODL)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<string> GetCurrOdlAsync(string idxMacchina)
|
|
{
|
|
string result = "";
|
|
string currKey = $"{Utils.redisOdlCurrByMac}:{idxMacchina}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = $"{rawData}";
|
|
}
|
|
else
|
|
{
|
|
result = await GetCurrOdlByProdAsync(idxMacchina);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il valOut dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza
|
|
/// ODL NO invio/gestione ODL)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="forceDb">indica se forzare lettura da db (true) o meno</param>
|
|
/// <returns></returns>
|
|
public async Task<string> GetCurrOdlAsync(string idxMacchina, bool forceDb)
|
|
{
|
|
string answ = "";
|
|
// se ho forceDB leggo dai dati prod...
|
|
if (forceDb)
|
|
{
|
|
var datiProd = await StatoProdMacchinaAsync(idxMacchina, DateTime.Now, true);
|
|
if (datiProd != null)
|
|
{
|
|
answ = datiProd.IdxOdl.ToString();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
answ = await GetCurrOdlAsync(idxMacchina);
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il valOut dell'ultimo ODL
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<ODLExpModel> GetLastOdlAsync(string idxMacchina)
|
|
{
|
|
ODLExpModel result = new ODLExpModel();
|
|
string currKey = $"{Utils.redisOdlLastByMac}:{idxMacchina}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<ODLExpModel>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.OdlLastByMaccAsync(idxMacchina);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua calcolo data-ora di riferimento per il server a partire da
|
|
/// </summary>
|
|
/// <param name="dtEve"></param>
|
|
/// <param name="dtCurr"></param>
|
|
/// <returns></returns>
|
|
public DateTime GetSrvDtEvent(string dtEve, string dtCurr)
|
|
{
|
|
DateTime dataOraEvento = DateTime.Now;
|
|
// 2017.09.14 trimmo eventualmente lo zero finale dalle date SE supera i millisecondi...
|
|
dtEve = dtEve.Length > 17 ? dtEve.Substring(0, 17) : dtEve;
|
|
dtCurr = dtCurr.Length > 17 ? dtCurr.Substring(0, 17) : dtCurr;
|
|
DateTime dtEvento, dtCorrente;
|
|
// controllo: se ho valori dt x evento e orario DIVERSI per acquisitore IOB calcolo
|
|
// dataOraEvento corretto
|
|
if (dtEve != dtCurr)
|
|
{
|
|
Int64 delta = 0;
|
|
try
|
|
{
|
|
// se ho meno decimali x evento rispetto dtCorrente...
|
|
if (dtEve.Length < dtCurr.Length)
|
|
{
|
|
dtEve = dtEve.PadRight(dtCurr.Length, '0');
|
|
}
|
|
delta = Convert.ToInt64(dtCurr) - Convert.ToInt64(dtEve);
|
|
// se meno di 60'000 ms ...
|
|
if (delta < 59999)
|
|
{
|
|
dataOraEvento = dataOraEvento.AddMilliseconds(-delta);
|
|
}
|
|
else
|
|
{
|
|
// in questo caso elimino i MS dalle stringhe e converto i datetime....
|
|
CultureInfo provider = CultureInfo.InvariantCulture;
|
|
string format = "yyyyMMddHHmmssfff";
|
|
dtEvento = DateTime.ParseExact(dtEve, format, provider);
|
|
dtCorrente = DateTime.ParseExact(dtCurr, format, provider);
|
|
TimeSpan deltaTS = dtCorrente.Subtract(dtEvento);
|
|
dataOraEvento = dataOraEvento.Add(-deltaTS);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"getSrvDtEvent | Errore calcolo ora corrente da IOB remoto | dtEve: {dtEve} | dtCurr: {dtCurr}{Environment.NewLine}" +
|
|
$"{exc}");
|
|
}
|
|
}
|
|
|
|
return dataOraEvento;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<Dictionary<string, string>> GetTask2ExeMacchinaAsync(string idxMacchina)
|
|
{
|
|
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
|
|
return await RedisGetHashDictAsync(currHash);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Init ricetta
|
|
/// </summary>
|
|
/// <param name="confPath"></param>
|
|
/// <param name="idxPODL"></param>
|
|
/// <param name="CalcArgs"></param>
|
|
/// <returns></returns>
|
|
public RecipeModel InitRecipe(string confPath, int idxPODL, Dictionary<string, string> CalcArgs)
|
|
{
|
|
return mongoController.InitRecipe(confPath, idxPODL, CalcArgs);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il valOut booleano se la macchina sia abilitata all'input
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> IobInsEnabAsync(string idxMacchina)
|
|
{
|
|
var key = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
|
|
|
string? val = await redisDb.HashGetAsync(key, "insEnabled");
|
|
|
|
if (val == null)
|
|
{
|
|
var data = await ResetDatiMacchinaAsync(idxMacchina);
|
|
data.TryGetValue("insEnabled", out val);
|
|
}
|
|
|
|
return val != null && (val == "1" || val.ToLower() == "true");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il valOut booleano se la macchina sia master
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> IobIsMasterAsync(string idxMacchina)
|
|
{
|
|
var key = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
|
|
|
// 1. Tentativo ottimizzato: leggiamo solo il campo che ci serve
|
|
// Supponendo che tu usi StackExchange.Redis direttamente o un wrapper
|
|
string? val = await redisDb.HashGetAsync(key, "Master");
|
|
|
|
// 2. Se non c'è in cache, carichiamo/resettiamo tutto
|
|
if (val == null)
|
|
{
|
|
//var data = ResetDatiMacchina(idxMacchina);
|
|
var data = await ResetDatiMacchinaAsync(idxMacchina);
|
|
data.TryGetValue("Master", out val);
|
|
}
|
|
|
|
// 3. Parsing sicuro
|
|
return val != null && (val == "1" || val.ToLower() == "true");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il valOut booleano se la macchina sia abilitata all'inserimento COMPLETO nel
|
|
/// Signal Log
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> IobSLogEnabAsync(string idxMacchina)
|
|
{
|
|
bool answ = false;
|
|
// ORA recupero da memoria redis...
|
|
try
|
|
{
|
|
var currHash = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
|
RedisValue rawData = await redisDb.HashGetAsync(currHash, (RedisValue)"sLogEnabled");
|
|
// se è vuoto... leggo da DB e popolo!
|
|
if (!rawData.HasValue)
|
|
{
|
|
await ResetDatiMacchinaAsync(idxMacchina);
|
|
// riprovo
|
|
rawData = await redisDb.HashGetAsync(currHash, (RedisValue)"sLogEnabled");
|
|
}
|
|
|
|
// provo conversione
|
|
bool.TryParse($"{rawData}", out answ);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore IobSLogEnabAsync | idxMacchina {idxMacchina}:{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="IdxOdl">idxMacc odl da cercare</param>
|
|
/// <returns></returns>
|
|
public async Task<List<AnagGiacenzeModel>> ListGiacenze(int IdxOdl)
|
|
{
|
|
List<AnagGiacenzeModel>? result = new List<AnagGiacenzeModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisGiacenzaList}:{IdxOdl}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<AnagGiacenzeModel>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.ListGiacenze(IdxOdl));
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<AnagGiacenzeModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"ListGiacenze | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
public async Task<List<ListValuesModel>> ListValuesFilt(string tabName, string fieldName)
|
|
{
|
|
List<ListValuesModel> resultList = new List<ListValuesModel>();
|
|
string tag = "";
|
|
tag += string.IsNullOrEmpty(tabName) ? "" : $"{tabName}:";
|
|
tag += string.IsNullOrEmpty(fieldName) ? "" : $"{fieldName}:";
|
|
var currKey = $"{Utils.redisConfFlux}:{tag}";
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
resultList = JsonConvert.DeserializeObject<List<ListValuesModel>>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
resultList = await IocDbController.ListValuesFiltAsync(tabName, fieldName);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(resultList);
|
|
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (resultList == null)
|
|
{
|
|
resultList = new();
|
|
}
|
|
return resultList;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco completo valori Macchine 2 Slave
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<List<Macchine2SlaveModel>> Macchine2SlaveGetAllAsync()
|
|
{
|
|
List<Macchine2SlaveModel>? result = new List<Macchine2SlaveModel>();
|
|
string currKey = $"{Utils.redisBaseAddr}:M2STab";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<Macchine2SlaveModel>>($"{rawData}");
|
|
}
|
|
else
|
|
{
|
|
if (useFactory)
|
|
{
|
|
await using var scope = _scopeFactory.CreateAsyncScope();
|
|
var mtcService = scope.ServiceProvider.GetRequiredService<MpIocController>();
|
|
result = await mtcService.Macchine2SlaveAsync();
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.Macchine2SlaveAsync();
|
|
}
|
|
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<Macchine2SlaveModel>();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco di tutte le macchine gestite
|
|
/// </summary>
|
|
/// <param name="codGruppo"></param>
|
|
/// <returns></returns>
|
|
public async Task<List<MacchineModel>> MacchineGetFilt(string codGruppo)
|
|
{
|
|
List<MacchineModel>? result = new List<MacchineModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string keyGrp = codGruppo != "*" ? codGruppo : "ALL";
|
|
string currKey = $"{Utils.redisMacList}:{keyGrp}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<MacchineModel>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.MacchineGetFilt(codGruppo));
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<MacchineModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"MacchineGetAll | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica se la macchina abbia un codice PATH ricette associato
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<string> MacchineRecipeArchive(string idxMacchina)
|
|
{
|
|
string? result = "";
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisMacRecipePath}:{idxMacchina}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<string>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
//recupero elenco macchine...
|
|
var machineList = await MacchineGetFilt("*");
|
|
var currMach = machineList.Where(x => x.IdxMacchina == idxMacchina).FirstOrDefault();
|
|
result = currMach != null ? currMach.RecipeArchivePath : null;
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"MacchineRecipeArchive | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result ?? "";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica se la macchina abbia un codice CONF ricetta associato
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<string> MacchineRecipeConf(string idxMacchina)
|
|
{
|
|
string? result = "";
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisMacRecipeConf}:{idxMacchina}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<string>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
//recupero elenco macchine...
|
|
var machineList = await MacchineGetFilt("*");
|
|
var currMach = machineList.Where(x => x.IdxMacchina == idxMacchina).FirstOrDefault();
|
|
result = currMach != null ? currMach.RecipePath : null;
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"MacchineRecipeConf | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result ?? "";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco idxMacc Macchine che abbiano dati FLuxLog, nel periodo indicato
|
|
/// </summary>
|
|
/// <param name="dtStart"></param>
|
|
/// <param name="dtEnd"></param>
|
|
/// <returns></returns>
|
|
public async Task<List<string>> MacchineWithFlux(DateTime dtStart, DateTime dtEnd)
|
|
{
|
|
List<string>? result = new List<string>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisMacByFlux}:{dtStart:yyyyMMddHHmm}:{dtEnd:yyyyMMddHHmm}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<string>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await SpecDbController.MacchineWithFlux(dtStart, dtEnd);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<string>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"MacchineWithFlux | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lista parametri correnti (ObjItemDTO) della macchina (ex getCurrObjItems)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public List<ObjItemDTO> MachineParamList(string idxMacchina)
|
|
{
|
|
// setup parametri costanti
|
|
string source = "NA";
|
|
Stopwatch sw = new Stopwatch();
|
|
sw.Start();
|
|
List<ObjItemDTO>? result = new List<ObjItemDTO>();
|
|
// cerco in _redisConn...
|
|
var currKey = Utils.RedKeyCurrObjItems(idxMacchina, MpIoNS);
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue && rawData.Length() > 2)
|
|
{
|
|
var rawVal = JsonConvert.DeserializeObject<List<ObjItemDTO>>($"{rawData}");
|
|
// ordino!
|
|
result = rawVal
|
|
.OrderBy(x => x.displOrdinal)
|
|
.ThenBy(x => x.description)
|
|
.ToList();
|
|
source = "REDIS";
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<ObjItemDTO>();
|
|
source = "NONE";
|
|
}
|
|
sw.Stop();
|
|
Log.Debug($"MachineParamList | {source} | {sw.Elapsed.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lista parametri correnti (ObjItemDTO) della macchina (ex getCurrObjItems)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<List<ObjItemDTO>> MachineParamListAsync(string idxMacchina)
|
|
{
|
|
// setup parametri costanti
|
|
string source = "NA";
|
|
Stopwatch sw = new Stopwatch();
|
|
sw.Start();
|
|
List<ObjItemDTO>? result = new List<ObjItemDTO>();
|
|
// cerco in _redisConn...
|
|
var currKey = Utils.RedKeyCurrObjItems(idxMacchina, MpIoNS);
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue && rawData.Length() > 2)
|
|
{
|
|
var rawVal = JsonConvert.DeserializeObject<List<ObjItemDTO>>($"{rawData}");
|
|
// ordino!
|
|
result = rawVal
|
|
.OrderBy(x => x.displOrdinal)
|
|
.ThenBy(x => x.description)
|
|
.ToList();
|
|
source = "REDIS";
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<ObjItemDTO>();
|
|
source = "NONE";
|
|
}
|
|
sw.Stop();
|
|
Log.Debug($"MachineParamListAsync | {source} | {sw.Elapsed.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lista parametri correnti che necessitano di write della macchina (ex getCurrObjItems)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<List<ObjItemDTO>> MachineParamListPendingWriteAsync(string idxMacchina)
|
|
{
|
|
List<ObjItemDTO>? result = new List<ObjItemDTO>();
|
|
// recupero tutti i parametri
|
|
var allData = await MachineParamListAsync(idxMacchina);
|
|
result = allData.Where(x => x.writable && !string.IsNullOrEmpty(x.reqValue)).ToList();
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue aggiornamento MachineParamList (ex CurrObjItems) Async
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="currData"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> MachineParamListSetAsync(string idxMacchina, List<ObjItemDTO> currData)
|
|
{
|
|
string serVal = JsonConvert.SerializeObject(currData);
|
|
var currKey = Utils.RedKeyCurrObjItems(idxMacchina, MpIoNS);
|
|
bool fatto = await redisDb.StringSetAsync(currKey, serVal);
|
|
return fatto;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua UPSERT elenco parametri correnti x IOB (se c'è UPDATE, se manca ADD)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="innovations"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> MachineParamUpsertAsync(string idxMacchina, List<ObjItemDTO> innovations)
|
|
{
|
|
bool answ = false;
|
|
if (innovations != null)
|
|
{
|
|
Log.Info($"upsertCurrObjItems | idxMacchina: {idxMacchina} | {innovations.Count} innovations");
|
|
// leggo i valori attuali...
|
|
List<ObjItemDTO> actValues = await MachineParamListAsync(idxMacchina);
|
|
// per ogni valOut passatomi faccio insert o update rispetto elenco valori correnti
|
|
// in REDIS
|
|
foreach (var item in actValues)
|
|
{
|
|
// cerco nelle innovazioni SE CI SIA il valOut...
|
|
var trovato = innovations.Find(obj => obj.uid == item.uid);
|
|
// se non trovato nelle innovazioni...
|
|
if (trovato == null)
|
|
{
|
|
// lo ri-aggiungo x non perderlo
|
|
innovations.Add(item);
|
|
// in base a value (value == null) uso debug/info
|
|
if (string.IsNullOrEmpty(item.value))
|
|
{
|
|
Log.Debug($"idxMacchina: {idxMacchina} | innovations | add | item.uid: {item.uid} | item.value: {item.value}");
|
|
}
|
|
else
|
|
{
|
|
Log.Info($"idxMacchina: {idxMacchina} | innovations | add | item.uid: {item.uid} | item.value: {item.value}");
|
|
}
|
|
}
|
|
// altrimenti aggiorno campo (non trasmesso) name e tengo il resto...
|
|
else
|
|
{
|
|
trovato.name = item.name;
|
|
Log.Debug($"idxMacchina: {idxMacchina} | innovations | update | item.uid: {item.uid} | item.value: {item.value} --> {trovato.value} ");
|
|
}
|
|
}
|
|
// serializzo e salvo
|
|
answ = await MachineParamListSetAsync(idxMacchina, innovations);
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP dei campi DatiMacchine + StatoMacchine per l'impianto indicato
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<Dictionary<string, string>> mDatiMacchineAsync(string idxMacchina)
|
|
{
|
|
// hard coded dimensione vettore DatiMacchine
|
|
Dictionary<string, string> answ = new Dictionary<string, string>();
|
|
// ORA recupero da memoria redis...
|
|
try
|
|
{
|
|
var currHash = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
|
answ = await RedisGetHashDictAsync(currHash);
|
|
// se è vuoto... leggo da DB e popolo!
|
|
if (answ.Count == 0)
|
|
{
|
|
answ = await ResetDatiMacchinaAsync(idxMacchina);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in compilazione dati Macchine x Redis - idxMacchina {idxMacchina}:{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public Dictionary<string, string> mOptParMacchina(string idxMacchina)
|
|
{
|
|
// hard coded dimensione vettore DatiMacchine
|
|
Dictionary<string, string> answ = new Dictionary<string, string>();
|
|
// ORA recupero da memoria redis...
|
|
RedisKey currHash = Utils.RedKeyOptPar(idxMacchina, MpIoNS);
|
|
answ = RedisGetHashDict(currHash);
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP dei TASK SALVATI (da passare a IOB-WIN) per l'impianto indicato
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public Dictionary<string, string> mSavedTaskMacchina(string idxMacchina)
|
|
{
|
|
// hard coded dimensione vettore DatiMacchine
|
|
Dictionary<string, string> answ = new Dictionary<string, string>();
|
|
// ORA recupero da memoria redis...
|
|
try
|
|
{
|
|
RedisKey currHash = Utils.RedKeySavedTask2ExeMacc(idxMacchina);
|
|
answ = RedisGetHashDict(currHash);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Info($"Errore in recupero dati SAVED TASK x Redis mSavedTaskMacchina | idxMacchina {idxMacchina}{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco da tabella MappaStatoExplModel
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<List<MappaStatoExplModel>> MseGetAllAsync(bool forceDb = false)
|
|
{
|
|
Stopwatch sw = new Stopwatch();
|
|
string source = "DB";
|
|
sw.Start();
|
|
List<MappaStatoExplModel>? result = new List<MappaStatoExplModel>();
|
|
// cerco in _redisConn...
|
|
RedisValue rawData = await redisDb.StringGetAsync(Constants.redisMseKey);
|
|
if (rawData.HasValue && !forceDb)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<MappaStatoExplModel>>($"{rawData}") ?? new();
|
|
source = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.MseGetAllAsync(maxAge);
|
|
// serializzp e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(Constants.redisMseKey, rawData, getRandTOut(redisShortTimeCache / 2));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<MappaStatoExplModel>();
|
|
}
|
|
sw.Stop();
|
|
Log.Debug($"MseGetAllAsync | {source} | {sw.Elapsed.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP (async) per evitare blocchi quando chiamato da metodi asincroni
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<KeyValuePair<string, string>[]> mTabMSMIAsync(string idxMacchina)
|
|
{
|
|
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[1];
|
|
answ[0] = new KeyValuePair<string, string>("0", "0");
|
|
try
|
|
{
|
|
var currHash = Utils.RedKeyMsmi(idxMacchina);
|
|
answ = await RedisGetHashAsync(currHash);
|
|
if (answ == null || answ.Length == 0)
|
|
{
|
|
answ = await resetMSMIAsync(idxMacchina);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in compilazione Tabella Multi State Machine Ingressi x Redis:{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public Dictionary<string, string> mTaskMacchina(string idxMacchina)
|
|
{
|
|
// hard coded dimensione vettore DatiMacchine
|
|
Dictionary<string, string> answ = new Dictionary<string, string>();
|
|
// ORA recupero da memoria redis...
|
|
try
|
|
{
|
|
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
|
|
answ = RedisGetHashDict(currHash);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error(string.Format("Errore in mTaskMacchina | idxMacchina {2}:{0}{1}", Environment.NewLine, exc, idxMacchina));
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<Dictionary<string, string>> mTaskMacchinaAsync(string idxMacchina)
|
|
{
|
|
// hard coded dimensione vettore DatiMacchine
|
|
Dictionary<string, string> answ = new Dictionary<string, string>();
|
|
// ORA recupero da memoria redis...
|
|
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
|
|
answ = await RedisGetHashDictAsync(currHash);
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generazione autoOdl
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="dataInizio"></param>
|
|
/// <param name="dataFine"></param>
|
|
/// <param name="codArticolo"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> OdlAutoDayGenAsync(string idxMacchina, DateTime dataInizio, DateTime dataFine, string codArticolo)
|
|
{
|
|
var result = await IocDbController.OdlAutoDayGenAsync(idxMacchina, dataInizio, dataFine, codArticolo);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generazione autoOdl
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="dataInizio"></param>
|
|
/// <param name="dataFine"></param>
|
|
/// <param name="codArticolo"></param>
|
|
/// <param name="pzPODL"></param>
|
|
/// <param name="pzPallet"></param>
|
|
/// <param name="keyRichiesta"></param>
|
|
/// <param name="tcAssegnato"></param>
|
|
/// <param name="codGruppo"></param>
|
|
/// <param name="flgCreaPODL"></param>
|
|
/// <param name="flgCheckTC"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> OdlAutoDayGenFullAsync(string idxMacchina, DateTime dataInizio, DateTime dataFine, string codArticolo, int? pzPODL, int? pzPallet, string? keyRichiesta, int? tcAssegnato, string? codGruppo, bool flgCreaPODL, bool flgCheckTC)
|
|
{
|
|
var result = await IocDbController.OdlAutoDayGenFullAsync(idxMacchina, dataInizio, dataFine, codArticolo, pzPODL, pzPallet, keyRichiesta, tcAssegnato, codGruppo, flgCreaPODL, flgCheckTC);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco ODL dato batch selezionato
|
|
/// </summary>
|
|
/// <param name="BatchSel">Batch richiesto</param>
|
|
/// <returns></returns>
|
|
public async Task<List<int>> OdlByBatch(string BatchSel)
|
|
{
|
|
List<int>? result = new List<int>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = Utils.redisOdlByBatch;
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<int>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.OdlByBatch(BatchSel));
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<int>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"OdlByBatch | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// ODL da chiave
|
|
/// </summary>
|
|
/// <param name="IdxOdl"></param>
|
|
/// <returns></returns>
|
|
public ODLExpModel OdlByKey(int IdxOdl)
|
|
{
|
|
ODLExpModel? result = new ODLExpModel();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
result = SpecDbController.OdlByKey(IdxOdl);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"OdlByKey | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua chiusura dell'ODL indicato, andand
|
|
/// </summary>
|
|
/// <param name="idxOdl">idx odl da chiudere</param>
|
|
/// <param name="idxMacchina">idx macchina</param>
|
|
/// <param name="matrOpr">matricola operatore</param>
|
|
/// <param name="confPezzi">indica se confermare i pezzi priam di chiudere ODL</param>
|
|
public async Task<bool> ODLClose(int idxOdl, string idxMacchina, int matrOpr, bool confPezzi)
|
|
{
|
|
bool fatto = false;
|
|
await Task.Delay(1);
|
|
// recupero dati x conf modalità conferma
|
|
var configData = await ConfigGetAllAsync();
|
|
if (configData != null)
|
|
{
|
|
bool confRett = false;
|
|
var currRec = configData.FirstOrDefault(x => x.Chiave == "confRett");
|
|
if (currRec != null)
|
|
{
|
|
bool.TryParse(currRec.Valore, out confRett);
|
|
}
|
|
int modoConfProd = 0;
|
|
currRec = configData.FirstOrDefault(x => x.Chiave == "modoConfProd");
|
|
if (currRec != null)
|
|
{
|
|
int.TryParse(currRec.Valore, out modoConfProd);
|
|
}
|
|
// chiamo metodo conferma!
|
|
fatto = await SpecDbController.ODLClose(idxOdl, idxMacchina, matrOpr, confPezzi, confRett, modoConfProd);
|
|
}
|
|
|
|
return fatto;
|
|
}
|
|
|
|
public async Task<ODLExpModel> OdlCurrByMaccAsync(string IdxMacchina)
|
|
{
|
|
ODLExpModel result = new();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisOdlList}:Current:{IdxMacchina}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<ODLExpModel>($"{rawData}") ?? new();
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.OdlCurrByMaccAsync(IdxMacchina);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Trace($"OdlCurrByMaccAsync | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Record ODL da chaive
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<ODLModel> OdlGetByKey(int IdxOdl)
|
|
{
|
|
await Task.Delay(1);
|
|
var dbResult = await SpecDbController.OdlGetByKey(IdxOdl);
|
|
return dbResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// ODL correnti (tutti)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public List<string> OdlGetCurrent()
|
|
{
|
|
List<string>? dbResult = new List<string>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisOdlCurrByMac}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
try
|
|
{
|
|
dbResult = JsonConvert.DeserializeObject<List<string>>($"{rawData}");
|
|
}
|
|
catch
|
|
{ }
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
dbResult = SpecDbController.OdlGetCurrent().Select(x => x.IdxMacchina).Distinct().ToList();
|
|
rawData = JsonConvert.SerializeObject(dbResult);
|
|
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(3));
|
|
}
|
|
if (dbResult == null)
|
|
{
|
|
dbResult = new List<string>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"OdlGetCurrent | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
|
|
return dbResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// elenco TUTTI gli ODL
|
|
/// </summary>
|
|
/// <param name="IdxOdl"></param>
|
|
/// <returns></returns>
|
|
public List<ODLModel> OdlListAll()
|
|
{
|
|
List<ODLModel>? result = new List<ODLModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
result = SpecDbController.OdlListAll();
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"OdlListAll | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco ODL filtrati x stato, articolo, KeyRich (che contiene stato)
|
|
/// </summary>
|
|
/// <param name="inCorso">Stato ODL: true=in corso/completato</param>
|
|
/// <param name="codArt">Cod articolo</param>
|
|
/// <param name="keyRichPart">KeyRich (parziale) da cercare (es cod stato x yacht)</param>
|
|
/// <param name="Reparto">Reparto selezionato</param>
|
|
/// <param name="IdxMacchina">Macchina selezionata</param>
|
|
/// <param name="startDate">Data inizio</param>
|
|
/// <param name="endDate">Data fine</param>
|
|
/// <returns></returns>
|
|
public async Task<List<ODLExpModel>> OdlListGetFilt(bool inCorso, string codArt, string keyRichPart, string Reparto, string IdxMacchina, DateTime startDate, DateTime endDate)
|
|
{
|
|
List<ODLExpModel>? result = new List<ODLExpModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisOdlList}:{inCorso}:{codArt}:{keyRichPart}:{Reparto}:{IdxMacchina}:{startDate:yyyyMMdd_HHmmss}:{endDate:yyyyMMdd_HHmmss}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<ODLExpModel>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.ListODLFilt(inCorso, codArt, keyRichPart, Reparto, IdxMacchina, startDate, endDate));
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<ODLExpModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"OdlListGetFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco di tutti i parametri filtrati x macchina
|
|
/// </summary>
|
|
/// <param name="IdxMacchina">* = tutte, altrimenti solo x una data macchina</param>
|
|
/// <returns></returns>
|
|
public async Task<List<string>> ParametriGetFilt(string IdxMacchina)
|
|
{
|
|
List<string>? result = new List<string>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisFluxByMac}:{IdxMacchina}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<string>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.ParametriGetFilt(IdxMacchina));
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<string>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"ParametriGetFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Eliminazione record selezionato
|
|
/// </summary>
|
|
/// <param name="currRec"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> POdlDeleteRecord(PODLExpModel currRec)
|
|
{
|
|
var dbResult = await SpecDbController.PODLDeleteRecord(currRec);
|
|
// elimino cache redis...
|
|
await POdlFlushCache();
|
|
await Task.Delay(1);
|
|
return dbResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Avvio fase setup per il record selezionato
|
|
/// </summary>
|
|
/// <param name="currRec"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> POdlDoSetup(PODLExpModel currRec)
|
|
{
|
|
var dbResult = await SpecDbController.PODL_startSetup(currRec, 0, 1, 1, "", DateTime.Now);
|
|
// elimino cache redis...
|
|
await POdlFlushCache();
|
|
await Task.Delay(1);
|
|
return dbResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recupero PODL da chiave
|
|
/// </summary>
|
|
/// <param name="idxPODL"></param>
|
|
/// <returns></returns>
|
|
public async Task<PODLModel> POdlGetByKey(int idxPODL)
|
|
{
|
|
PODLModel result = new PODLModel();
|
|
if (idxPODL != 0)
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisPOdlByPOdl}:{idxPODL}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
var rawResult = JsonConvert.DeserializeObject<PODLModel>($"{rawData}");
|
|
if (rawResult != null)
|
|
{
|
|
result = rawResult;
|
|
readType = "REDIS";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = await SpecDbController.PODL_getByKey(idxPODL);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new PODLModel();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Trace($"POdlGetByKey | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
}
|
|
else
|
|
{
|
|
Log.Debug("Errore IdxPODL = 0");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public async Task<List<PODLExpModel>> POdlGetByMaccArtAsync(string idxMacchina, string codArticolo, string codGruppo, bool onlyFree)
|
|
{
|
|
List<PODLExpModel> result = new List<PODLExpModel>();
|
|
|
|
var currKey = $"{Utils.redisPOdlByMaccArt}:{idxMacchina}";
|
|
if (!string.IsNullOrEmpty(codArticolo))
|
|
{
|
|
currKey += $":A{codArticolo}";
|
|
}
|
|
if (!string.IsNullOrEmpty(codGruppo))
|
|
{
|
|
currKey += $":G{codGruppo}";
|
|
}
|
|
currKey += onlyFree ? $":FREE" : ":ALL";
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<PODLExpModel>>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.POdlGetByMaccArtAsync(idxMacchina, codArticolo, codGruppo, onlyFree);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<PODLExpModel>();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recupero PODL da IdxODL
|
|
/// </summary>
|
|
/// <param name="idxODL"></param>
|
|
/// <returns></returns>
|
|
public PODLModel POdlGetByOdl(int idxODL)
|
|
{
|
|
PODLModel result = new PODLModel();
|
|
if (idxODL != 0)
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisPOdlByOdl}:{idxODL}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
var rawResult = JsonConvert.DeserializeObject<PODLModel>($"{rawData}");
|
|
if (rawResult != null)
|
|
{
|
|
result = rawResult;
|
|
}
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = SpecDbController.PODL_getByOdl(idxODL);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new PODLModel();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Trace($"POdlGetByOdl | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
}
|
|
else
|
|
{
|
|
Log.Debug("Errore IdxODL = 0");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco PODL non avviati filtrati x articolo, KeyRich (che contiene stato)
|
|
/// </summary>
|
|
/// <param name="lanciato">Solo lanciati (1) o ancora disponibili (0)</param>
|
|
/// <param name="keyRichPart">KeyRich (parziale) da cercare (es cod stato x yacht)</param>
|
|
/// <param name="idxMacchina">Macchina</param>
|
|
/// <param name="codGruppo">Gruppo</param>
|
|
/// <param name="startDate">Data inizio</param>
|
|
/// <param name="endDate">Data fine</param>
|
|
/// <returns></returns>
|
|
public async Task<List<PODLExpModel>> POdlListGetFilt(bool lanciato, string keyRichPart, string idxMacchina, string codGruppo, DateTime startDate, DateTime endDate)
|
|
{
|
|
List<PODLExpModel>? result = new List<PODLExpModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisPOdlList}:{codGruppo}:{idxMacchina}:{keyRichPart}:{lanciato}:{startDate:yyyyMMdd_HHmmss}:{endDate:yyyyMMdd_HHmmss}";
|
|
// cerco in redis dato valOut sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<PODLExpModel>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await Task.FromResult(SpecDbController.ListPODLFilt(lanciato, keyRichPart, idxMacchina, codGruppo, startDate, endDate));
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<PODLExpModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"POdlListGetFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aggiornamento record selezionato
|
|
/// </summary>
|
|
/// <param name="currRec"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> POdlUpdateRecord(PODLModel currRec)
|
|
{
|
|
var dbResult = await SpecDbController.PODLUpdateRecord(currRec);
|
|
// elimino cache redis...
|
|
await POdlFlushCache();
|
|
return dbResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processa registrazione FL da IOB
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="flux"></param>
|
|
/// <param name="valore"></param>
|
|
/// <param name="dtEve"></param>
|
|
/// <param name="dtCurr"></param>
|
|
/// <param name="contatore"></param>
|
|
/// <param name="disabKA"></param>
|
|
/// <returns></returns>
|
|
public async Task<string> ProcessFluxLogAsync(string idxMacchina, string flux, string valore, string dtEve, string dtCurr, int contatore, bool disabKA)
|
|
{
|
|
// se non vietato...
|
|
if (!disabKA)
|
|
{
|
|
// scrivo keep alive!!! (se necessario, altrimenti è in cache...)
|
|
await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
|
|
}
|
|
|
|
string answ = "";
|
|
DateTime dataOraEvento = GetSrvDtEvent(dtEve, dtCurr);
|
|
// inizio processing vero e proprio INPUT...
|
|
|
|
if (string.IsNullOrEmpty(idxMacchina) || string.IsNullOrEmpty(valore))
|
|
{
|
|
string errore = "processFluxLog | Errore: parametri macchina/valOut vuoti";
|
|
Log.Error(errore);
|
|
answ = errore;
|
|
}
|
|
else
|
|
{
|
|
FluxLogModel newRec = new FluxLogModel()
|
|
{
|
|
IdxMacchina = idxMacchina,
|
|
dtEvento = dataOraEvento,
|
|
CodFlux = flux,
|
|
Valore = valore,
|
|
Cnt = contatore
|
|
};
|
|
await IocDbController.FluxLogInsertAsync(newRec);
|
|
// 2022.06.06 salvo su redis il valOut ULTIMO del flux x recupero rapido ultimo valOut
|
|
var currKey = Utils.RedKeyLastFLog(idxMacchina, flux, MpIoNS);
|
|
// 10 min cache max...
|
|
await redisDb.StringSetAsync(currKey, valore, TimeSpan.FromMinutes(10));
|
|
// registro in risposta che è andato tutto bene...
|
|
answ = "OK";
|
|
}
|
|
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validazione preliminare valori input
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="valore"></param>
|
|
/// <param name="dtEve"></param>
|
|
/// <param name="dtCurr"></param>
|
|
/// <returns></returns>
|
|
private bool ValidateinputParams(string idxMacchina, string valore, string dtEve, string dtCurr)
|
|
{
|
|
bool isValid = false;
|
|
// preparo stringa valori correnti
|
|
string currVals = $"idxMacchina: {idxMacchina} | valOut: {valore} | dtEve: {dtEve} | dtCurr:{dtCurr}";
|
|
if (dtEve == null || dtCurr == null)
|
|
{
|
|
Log.Warn($"procInput: null found | {currVals}");
|
|
}
|
|
else if (dtEve.Length < 17 || dtCurr.Length < 17)
|
|
{
|
|
Log.Info($"procInput: invalid data | {currVals}");
|
|
}
|
|
else if (string.IsNullOrEmpty(idxMacchina))
|
|
{
|
|
Log.Info($"procInput: missing IdxMacchina | {currVals}");
|
|
}
|
|
else if (string.IsNullOrEmpty(valore))
|
|
{
|
|
Log.Info($"procInput: missing valOut | {currVals}");
|
|
}
|
|
else
|
|
{
|
|
isValid = true;
|
|
}
|
|
return isValid;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calcola dataora evento da info dt ricevute
|
|
/// </summary>
|
|
/// <param name="dtEve"></param>
|
|
/// <param name="dtCurr"></param>
|
|
/// <returns></returns>
|
|
private DateTime ParseEventTime(string dtEve, string dtCurr)
|
|
{
|
|
DateTime dataOraEvento = DateTime.Now;
|
|
|
|
// fix formato dataora in ingresso
|
|
string stdEve = dtFormStd(dtEve);
|
|
string stdCurr = dtFormStd(dtCurr);
|
|
|
|
// 2. Se le stringhe normalizzate coincidono, skip dei calcoli
|
|
if (stdEve != stdCurr)
|
|
{
|
|
// 3. Parsing sicuro
|
|
if (DateTime.TryParseExact(stdEve, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtEvento) &&
|
|
DateTime.TryParseExact(stdCurr, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtCorrente))
|
|
{
|
|
TimeSpan diff = dtCorrente - dtEvento;
|
|
double ms = Math.Abs(diff.TotalMilliseconds);
|
|
|
|
// 4. Classificazione delta con switch expression (più leggibile e performante)
|
|
string deltaClass = ms switch
|
|
{
|
|
<= 10 => "0-10 ms",
|
|
<= 100 => "10-100 ms",
|
|
<= 1000 => "100-1000 ms",
|
|
<= 10000 => "1-10 sec",
|
|
_ => "> 10 sec"
|
|
};
|
|
|
|
Log.Debug($"Correzione delta {deltaClass}");
|
|
|
|
// 5. Correzione data/ora server: sottrao lo scarto calcolato
|
|
dataOraEvento = dataOraEvento.Subtract(diff);
|
|
}
|
|
else
|
|
{
|
|
Log.Error($"Errore parsing date: {stdEve} | {stdCurr}");
|
|
}
|
|
}
|
|
return dataOraEvento;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processa input da IOB eventualmente registrando i segnali inviati
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="valore"></param>
|
|
/// <param name="dtEve"></param>
|
|
/// <param name="dtCurr"></param>
|
|
/// <param name="contatore"></param>
|
|
/// <returns></returns>
|
|
public async Task<string> ProcessInputAsync(string idxMacchina, string valore, string dtEve, string dtCurr, string contatore)
|
|
{
|
|
string answ = "";
|
|
if (ValidateinputParams(idxMacchina, valore, dtEve, dtCurr))
|
|
{
|
|
DateTime dataOraEvento = ParseEventTime(dtEve, dtCurr);
|
|
|
|
// se abilitato registro evento sul DB
|
|
if (await IobSLogEnabAsync(idxMacchina))
|
|
{
|
|
int cntVal = 0;
|
|
int.TryParse(contatore, out cntVal);
|
|
await saveSigLogAsync(idxMacchina, valore, dataOraEvento, cntVal);
|
|
}
|
|
// continuo col resto
|
|
try
|
|
{
|
|
// scrivo keep alive!!! (se necessario, altrimenti è in cache...)
|
|
await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
|
|
// Cache dati macchina per evitare lookup ridondanti
|
|
Dictionary<string, string> datiMacc = await mDatiMacchineAsync(idxMacchina);
|
|
// verifico se sia una macchina MULTI....
|
|
if (isMulti(idxMacchina, datiMacc))
|
|
{
|
|
// inizio preprocessing
|
|
string newVal = "";
|
|
// processo OGNI macchina a stati dell'impianto... (KEY:IdxMacchina / IdxMacchina#qualcosa, Val = IdxFamIn)
|
|
foreach (var item in await mTabMSMIAsync(idxMacchina))
|
|
{
|
|
newVal = preProcInput(item.Key, valore, datiMacc);
|
|
// ora processo e salvo il valOut del microstato...
|
|
// INTERNAMENTE gestisce i casi DB/REDIS secondo necessità
|
|
await CheckMicroStatoAsync(item.Key, newVal, dataOraEvento, contatore, datiMacc);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ora processo e salvo il valOut del microstato... INTERNAMENTE
|
|
// gestisce i casi DB/REDIS secondo necessità
|
|
await CheckMicroStatoAsync(idxMacchina, valore, dataOraEvento, contatore, datiMacc);
|
|
}
|
|
// forzo RESET dati macchina...
|
|
await ResetDatiMacchinaAsync(idxMacchina);
|
|
// registro in risposta che è andato tutto bene...
|
|
answ = "OK";
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
string errore = $"Errore: {Environment.NewLine}{exc}";
|
|
Log.Error(errore);
|
|
answ = errore;
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processa registrazione UserLog da IOB
|
|
/// </summary>
|
|
/// <param name="idxMacchina">Macchina</param>
|
|
/// <param name="flux">Flusso: DI/RC/RC</param>
|
|
/// <param name="valore">valOut = note/valString</param>
|
|
/// <param name="dtEve">data evento</param>
|
|
/// <param name="dtCurr">data corrente</param>
|
|
/// <param name="contatore">contatore invio</param>
|
|
/// <param name="matrOpr">Matricola Operatore</param>
|
|
/// <param name="label">label = causale scarto / tagCode</param>
|
|
/// <param name="valNum">valNum = esitoOk (0/1) / Quantità di scarto associata</param>
|
|
/// <returns></returns>
|
|
public async Task<string> ProcessUserLogAsync(string idxMacchina, string flux, string valore, string dtEve, string dtCurr, int contatore, int matrOpr, string label, int valNum)
|
|
{
|
|
// scrivo keep alive!!! (se necessario, altrimenti è in cache...)
|
|
await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
|
|
// 2017.09.14 trimmo eventualmente lo zero finale dalle date SE supera i millisecondi...
|
|
dtEve = dtEve.Length > 17 ? dtEve.Substring(0, 17) : dtEve;
|
|
dtCurr = dtCurr.Length > 17 ? dtCurr.Substring(0, 17) : dtCurr;
|
|
|
|
string answ = "";
|
|
DateTime dataOraEvento = GetSrvDtEvent(dtEve, dtCurr);
|
|
|
|
// inizio processing vero e proprio INPUT...
|
|
if (string.IsNullOrEmpty(idxMacchina) || string.IsNullOrEmpty(flux))
|
|
{
|
|
string errore = "processFluxLog | Errore: parametri macchina/flux vuoti";
|
|
Log.Error(errore);
|
|
answ = errore;
|
|
}
|
|
else
|
|
{
|
|
// in base al flusso decido dove e cosa scrivere...
|
|
switch (flux)
|
|
{
|
|
case "DI":
|
|
RegistroDichiarazioniModel recDich = new RegistroDichiarazioniModel()
|
|
{
|
|
IdxMacchina = idxMacchina,
|
|
DtRec = dataOraEvento,
|
|
MatrOpr = matrOpr,
|
|
ValString = valore,
|
|
TagCode = label
|
|
};
|
|
await IocDbController.RegDichiarInsertAsync(recDich);
|
|
break;
|
|
|
|
case "RC":
|
|
bool esitoOk = valNum != 0;
|
|
await IocDbController.RegControlliInsertAsync(idxMacchina, matrOpr, esitoOk, valore, dataOraEvento);
|
|
break;
|
|
|
|
case "RS":
|
|
RegistroScartiModel recSca = new RegistroScartiModel()
|
|
{
|
|
IdxMacchina = idxMacchina,
|
|
DataOra = dataOraEvento,
|
|
Causale = label,
|
|
Qta = valNum,
|
|
Note = valore,
|
|
MatrOpr = matrOpr
|
|
};
|
|
await IocDbController.RegScartiInsertAsync(recSca);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
// registro in risposta che è andato tutto bene...
|
|
answ = "OK";
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il contapezzi salvato per la macchina
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<int> pzCounter(string idxMacchina)
|
|
{
|
|
int answ = -1;
|
|
try
|
|
{
|
|
var currKey = Utils.RedKeyPzCount(idxMacchina, MpIoNS);
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
int.TryParse(rawData, out answ);
|
|
}
|
|
else
|
|
{
|
|
answ = await PzCounterTcAsync(idxMacchina);
|
|
// salvo in _redisConn...
|
|
await redisDb.StringSetAsync(currKey, answ.ToString(), TimeSpan.FromSeconds(1));
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in pzCounter{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il contapezzi come CONTEGGIO da TCRilevati per la macchina - ASYNC
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<int> PzCounterTcAsync(string idxMacchina)
|
|
{
|
|
int answ = -1;
|
|
DateTime dataRif = DateTime.Now;
|
|
var datiProd = await StatoProdMacchinaAsync(idxMacchina, dataRif);
|
|
if (datiProd != null)
|
|
{
|
|
answ = datiProd.PzTotODL;
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ricerca ricetta su MongoDB dato PODL
|
|
/// </summary>
|
|
/// <param name="idxPODL"></param>
|
|
/// <returns></returns>
|
|
public async Task<RecipeModel?> RecipeGetByPODL(int idxPODL)
|
|
{
|
|
RecipeModel? result = null;
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "MongoDB";
|
|
result = await mongoController.RecipeGetByPODL(idxPODL);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"RecipeGetByPODL | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Salva ricetta su MongoDB
|
|
/// </summary>
|
|
/// <param name="currRecord"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> RecipeSetByPODL(RecipeModel currRecord)
|
|
{
|
|
bool answ = false;
|
|
answ = await mongoController.RecipeSetByPODL(currRecord);
|
|
if (answ)
|
|
{
|
|
await POdlFlushCache();
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua conteggio chaivi REDIS dato pattern ricerca
|
|
/// </summary>
|
|
/// <param name="keyPattern"></param>
|
|
/// <returns></returns>
|
|
public int RedisCountKey(string keyPattern)
|
|
{
|
|
int num = 0;
|
|
keyPattern = (string.IsNullOrEmpty(keyPattern) ? "**" : keyPattern);
|
|
try
|
|
{
|
|
var listEndpoints = redisConnAdmin.GetEndPoints();
|
|
foreach (var endPoint in listEndpoints)
|
|
{
|
|
var server = redisConnAdmin.GetServer(endPoint);
|
|
foreach (RedisKey item in server.Keys(pattern: keyPattern, database: redisDb.Database, pageSize: 250, cursor: 0L))
|
|
{
|
|
num++;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception arg)
|
|
{
|
|
Log.Error($"Eccezione in RedisCountKey{Environment.NewLine}{arg}");
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue eliminazione memoria redis keyVal
|
|
/// </summary>
|
|
/// <param name="keyVal"></param>
|
|
/// <returns></returns>
|
|
public bool RedisDelKey(string keyVal)
|
|
{
|
|
bool answ = redisDb.KeyDelete((RedisKey)keyVal);
|
|
#if false
|
|
var listEndpoints = redisConnAdmin.GetEndPoints();
|
|
foreach (var endPoint in listEndpoints)
|
|
{
|
|
var server = redisConnAdmin.GetServer(endPoint);
|
|
if (server != null)
|
|
{
|
|
redisDb.KeyDelete((RedisKey)keyVal);
|
|
answ = true;
|
|
}
|
|
}
|
|
#endif
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue eliminazione memoria redis keyVal
|
|
/// </summary>
|
|
/// <param name="keyVal"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> RedisDelKeyAsync(RedisKey keyVal)
|
|
{
|
|
return await redisDb.KeyDeleteAsync(keyVal);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue flush memoria redis dato keyVal
|
|
/// </summary>
|
|
/// <param name="pattern"></param>
|
|
/// <returns></returns>
|
|
public bool RedisFlushPattern(string pattern)
|
|
{
|
|
bool answ = false;
|
|
var listEndpoints = redisConnAdmin.GetEndPoints();
|
|
foreach (var endPoint in listEndpoints)
|
|
{
|
|
var server = redisConnAdmin.GetServer(endPoint);
|
|
if (server != null)
|
|
{
|
|
var keyList = server.Keys(redisDb.Database, pattern);
|
|
foreach (var item in keyList)
|
|
{
|
|
redisDb.KeyDelete(item);
|
|
}
|
|
answ = true;
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue flush memoria redis dato keyVal, async
|
|
/// </summary>
|
|
/// <param name="pattern"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> RedisFlushPatternAsync(RedisValue pattern)
|
|
{
|
|
Log.Debug($"Richiesta flush pattern: {pattern}");
|
|
|
|
// 1. Target ONLY master (le replica sono in read-only)
|
|
var master = redisConnAdmin.GetEndPoints()
|
|
.Where(ep => redisConnAdmin.GetServer(ep).IsConnected && !redisConnAdmin.GetServer(ep).IsReplica)
|
|
.FirstOrDefault();
|
|
|
|
if (master == null)
|
|
{
|
|
Log.Warn($"Nessun master Redis raggiungibile per il pattern {pattern}");
|
|
return false;
|
|
}
|
|
|
|
// 2. Flush intero DB se richiesto
|
|
if (pattern.ToString() == "*")
|
|
{
|
|
Log.Debug($"Full DB reset da pattern {pattern}");
|
|
if (master != null)
|
|
{
|
|
redisConnAdmin.GetServer(master).FlushDatabase(redisDb.Database);
|
|
Log.Info($"Flush database {redisDb.Database} completato");
|
|
}
|
|
return true;
|
|
}
|
|
// altrimenti faccio ciclo!
|
|
var server = redisConnAdmin.GetServer(master);
|
|
var db = redisConnAdmin.GetDatabase(redisDb.Database);
|
|
const int batchSize = 500;
|
|
var batch = new List<RedisKey>(batchSize);
|
|
int deletedCount = 0;
|
|
|
|
try
|
|
{
|
|
// KeysAsync usa SCAN automaticamente quando i risultati sono grandi
|
|
await foreach (var key in server.KeysAsync(
|
|
database: redisDb.Database,
|
|
pattern: pattern.ToString(),
|
|
pageSize: batchSize))
|
|
{
|
|
batch.Add(key);
|
|
if (batch.Count >= batchSize)
|
|
{
|
|
// Esecuzione batch in parallelo controllato
|
|
await Task.WhenAll(batch.Select(k => db.KeyDeleteAsync(k)));
|
|
batch.Clear();
|
|
deletedCount += batchSize;
|
|
}
|
|
}
|
|
|
|
// Restanti
|
|
if (batch.Count > 0)
|
|
{
|
|
await Task.WhenAll(batch.Select(k => db.KeyDeleteAsync(k)));
|
|
deletedCount += batch.Count;
|
|
}
|
|
|
|
Log.Info("Flush pattern {Pattern}: eliminate {Count} chiavi", pattern, deletedCount);
|
|
return true;
|
|
}
|
|
catch (RedisConnectionException ex)
|
|
{
|
|
Log.Error(ex, "Connessione Redis persa durante il flush di {pattern}", pattern);
|
|
return false;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Errore imprevisto nel flush pattern {pattern}", pattern);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public KeyValuePair<string, string>[] RedisGetHash(RedisKey redKey)
|
|
{
|
|
HashEntry[] rawData = redisDb.HashGetAll(redKey);
|
|
var result = rawData.Where(x => !x.Name.IsNull).Select(x => new KeyValuePair<string, string>($"{x.Name}", $"{x.Value}")).ToArray();
|
|
return result;
|
|
}
|
|
|
|
public async Task<KeyValuePair<string, string>[]> RedisGetHashAsync(RedisKey redKey)
|
|
{
|
|
HashEntry[] rawData = await redisDb.HashGetAllAsync(redKey);
|
|
var result = rawData.Where(x => !x.Name.IsNull).Select(x => new KeyValuePair<string, string>($"{x.Name}", $"{x.Value}")).ToArray();
|
|
return result;
|
|
}
|
|
|
|
public Dictionary<string, string> RedisGetHashDict(RedisKey hashKey)
|
|
{
|
|
HashEntry[] rawData = redisDb.HashGetAll(hashKey);
|
|
var result = rawData.Where(x => !x.Name.IsNull).ToDictionary(x => x.Name.ToString(), x => x.Value.ToString());
|
|
return result;
|
|
}
|
|
|
|
public async Task<Dictionary<string, string>> RedisGetHashDictAsync(RedisKey hashKey)
|
|
{
|
|
HashEntry[] rawData = await redisDb.HashGetAllAsync(hashKey);
|
|
var result = rawData
|
|
.Where(x => !x.Name.IsNull)
|
|
.ToDictionary(x => x.Name.ToString(), x => x.Value.ToString());
|
|
return result;
|
|
}
|
|
|
|
public async Task<RedisValue> RedisGetHashFieldAsync(RedisKey key, string hashField)
|
|
{
|
|
return await redisDb.HashGetAsync(key, hashField);
|
|
}
|
|
|
|
public bool RedisKeyPresent(RedisKey key)
|
|
{
|
|
return redisDb.KeyExists(key);
|
|
}
|
|
|
|
public async Task<bool> RedisKeyPresentAsync(RedisKey key)
|
|
{
|
|
return await redisDb.KeyExistsAsync(key);
|
|
}
|
|
|
|
public void RedisSetHash(RedisKey redKey, KeyValuePair<string, string>[] valori, double expireSeconds = -1.0)
|
|
{
|
|
HashEntry[] redHash = valori.Select(x => new HashEntry(x.Key, x.Value)).ToArray();
|
|
redisDb.HashSet(redKey, redHash);
|
|
if (expireSeconds > 0.0)
|
|
{
|
|
redisDb.KeyExpire(redKey, DateTime.Now.AddSeconds(expireSeconds));
|
|
}
|
|
}
|
|
|
|
public async Task RedisSetHashAsync(RedisKey redKey, KeyValuePair<string, string>[] valori, double expireSeconds = -1.0)
|
|
{
|
|
HashEntry[] redHash = valori.Select(x => new HashEntry(x.Key, x.Value)).ToArray();
|
|
await redisDb.HashSetAsync(redKey, redHash);
|
|
if (expireSeconds > 0.0)
|
|
{
|
|
await redisDb.KeyExpireAsync(redKey, DateTime.Now.AddSeconds(expireSeconds));
|
|
}
|
|
}
|
|
|
|
public void RedisSetHashDict(RedisKey redKey, Dictionary<string, string> valori, double expireSeconds = -1.0)
|
|
{
|
|
HashEntry[] redHash = valori.Select(x => new HashEntry(x.Key, x.Value)).ToArray();
|
|
redisDb.HashSet(redKey, redHash);
|
|
if (expireSeconds > 0.0)
|
|
{
|
|
redisDb.KeyExpire(redKey, DateTime.Now.AddSeconds(expireSeconds));
|
|
}
|
|
}
|
|
|
|
public async Task RedisSetHashDictAsync(RedisKey redKey, Dictionary<string, string> valori, double expireSeconds = -1.0)
|
|
{
|
|
HashEntry[] redHash = valori.Select(x => new HashEntry(x.Key, x.Value)).ToArray();
|
|
await redisDb.HashSetAsync(redKey, redHash);
|
|
if (expireSeconds > 0.0)
|
|
{
|
|
await redisDb.KeyExpireAsync(redKey, DateTime.Now.AddSeconds(expireSeconds));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Inserisce record RRL + fa pulizia vecchi record
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<bool> RemRebootLogAddAsync(RemoteRebootLogModel newRec)
|
|
{
|
|
// verifica preliminare ultima esecuzione (max 1 ogni 60 min...)
|
|
DateTime adesso = DateTime.Now;
|
|
bool doClean = false;
|
|
if (adesso.Subtract(lastCleanupRRL).TotalMinutes > 60)
|
|
{
|
|
lastCleanupRRL = adesso;
|
|
doClean = true;
|
|
}
|
|
|
|
string confVal = await tryGetConfigAsync("IO_NumReboot2Keep");
|
|
int num2keep = int.TryParse(confVal, out int n) ? n : 5;
|
|
// insert del record + pulizia
|
|
bool fatto = await IocDbController.RemRebootLogAddAndCleanAsync(newRec, doClean, num2keep);
|
|
if (fatto)
|
|
{
|
|
// svuota cache
|
|
var currKey = $"{Utils.redisRemRebLog}:*";
|
|
await RedisFlushPatternAsync(currKey);
|
|
}
|
|
return fatto;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recupera tutti i record di RemoteRebootLog
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<List<RemoteRebootLogModel>> RemRebootLogGetAllAsync()
|
|
{
|
|
// setup parametri costanti
|
|
string source = "DB";
|
|
Stopwatch sw = new Stopwatch();
|
|
sw.Start();
|
|
List<RemoteRebootLogModel> result = new List<RemoteRebootLogModel>();
|
|
// cerco in _redisConn...
|
|
var currKey = $"{Utils.redisRemRebLog}:ALL";
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
//if (!string.IsNullOrEmpty($"{rawData}"))
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<RemoteRebootLogModel>>($"{rawData}") ?? new();
|
|
source = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.RemRebootLogGetAllAsync();
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(currKey, rawData, TimeSpan.FromSeconds(30));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<RemoteRebootLogModel>();
|
|
}
|
|
sw.Stop();
|
|
Log.Debug($"RemRebootLogGetAll | {source} | {sw.Elapsed.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recupera ultimo record x ogni IdxMacchina x avere ultimo attivo
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public async Task<List<RemoteRebootLogModel>> RemRebootLogGetLast()
|
|
{
|
|
// setup parametri costanti
|
|
string source = "DB";
|
|
Stopwatch sw = new Stopwatch();
|
|
sw.Start();
|
|
List<RemoteRebootLogModel> result = new List<RemoteRebootLogModel>();
|
|
// cerco in _redisConn...
|
|
var currKey = $"{Utils.redisRemRebLog}:LAST";
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<RemoteRebootLogModel>>($"{rawData}") ?? new();
|
|
source = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.RemRebootLogGetLastAsync();
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(currKey, rawData, TimeSpan.FromSeconds(30));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<RemoteRebootLogModel>();
|
|
}
|
|
sw.Stop();
|
|
Log.Debug($"RemRebootLogGetLast | {source} | {sw.Elapsed.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elimina da elenco KVP il TASK per l'impianto indicato
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="tName"></param>
|
|
/// <returns></returns>
|
|
public async Task<Dictionary<string, string>> RemTask2ExeMacchinaAsync(string idxMacchina, taskType tName)
|
|
{
|
|
// hard coded dimensione vettore DatiMacchine
|
|
Dictionary<string, string> answ = new Dictionary<string, string>();
|
|
// ORA recupero da memoria redis...
|
|
try
|
|
{
|
|
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
|
|
answ = await RedisGetHashDictAsync(currHash);
|
|
|
|
answ.Remove($"{tName}");
|
|
// riscrivo!
|
|
await RedisDelKeyAsync(currHash);
|
|
await RedisSetHashDictAsync(currHash, answ);
|
|
Log.Info($"Task REM - idxMacchina: {idxMacchina} | taskKey: {tName.ToString()}");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Info(string.Format("Errore in RemTask2ExeMacchinaAsync | idxMacchina {2}:{0}{1}", Environment.NewLine, exc, idxMacchina));
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resetta (rileggendo) i dati della State Machine multi ingressi nel formato
|
|
/// currKey: IdxMacchina
|
|
/// value: IdxFamigliaIngresso
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task<KeyValuePair<string, string>[]> resetMSMIAsync(string idxMacchina)
|
|
{
|
|
var currHash = Utils.RedKeyMsmi(idxMacchina);
|
|
// recupero records
|
|
var tabMSMI = await IocDbController.VMSFDGetMultiByMaccAsync(idxMacchina);
|
|
|
|
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[tabMSMI.Count];
|
|
// salvo tutti i valori StateMachineIngressi...
|
|
int i = 0;
|
|
foreach (var item in tabMSMI)
|
|
{
|
|
answ[i] = new KeyValuePair<string, string>(item.IdxMacchina, item.IdxFamigliaIngresso.ToString());
|
|
i++;
|
|
}
|
|
// verifico il timeout (default 60 sec...)
|
|
var sTOutSmi = await tryGetConfigAsync("TmOut.MSMI");
|
|
int tOut = 60;
|
|
int.TryParse(sTOutSmi, out tOut);
|
|
tOut = tOut <= 60 ? 60 : tOut;
|
|
// salvo in redis!
|
|
await RedisSetHashAsync(currHash, answ, tOut);
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processa registrazione EVENTO CONTEGGIO PEZZI x una data macchina IOB
|
|
/// </summary>
|
|
/// <param name="idxMacchina">Macchina</param>
|
|
/// <param name="qty">Pezzi da registrare</param>
|
|
/// <returns></returns>
|
|
public async Task<string> saveCaricoPezzi(string idxMacchina, string qty)
|
|
{
|
|
// default: 0, non registrato x cautela...
|
|
string answ = "0";
|
|
// controllo per proseguire
|
|
if (string.IsNullOrEmpty(idxMacchina) || string.IsNullOrEmpty(qty))
|
|
{
|
|
string errore = $"Errore: mancano parametri macchina/incremento: idxMacchina {idxMacchina} | qty {qty}";
|
|
Log.Error(errore);
|
|
answ = errore;
|
|
}
|
|
else
|
|
{
|
|
int numPzIncr = -1;
|
|
int.TryParse(qty, out numPzIncr);
|
|
// se il conteggio è >= 0 SALVO evento...
|
|
if (numPzIncr >= 0)
|
|
{
|
|
// recupero info tra cui ODL corrente
|
|
Dictionary<string, string> datiMacc = await mDatiMacchineAsync(idxMacchina);
|
|
// registro evento 120 --> contapezzi in blocco !!!HARD CODED!!! !!!FIXME!!!
|
|
int idxEvento = 120;
|
|
DateTime adesso = DateTime.Now;
|
|
string codArticolo = "ND";
|
|
if (datiMacc.ContainsKey("CodArticolo"))
|
|
{
|
|
codArticolo = datiMacc["CodArticolo"];
|
|
}
|
|
|
|
// creo evento
|
|
EventListModel newRecEv = new EventListModel()
|
|
{
|
|
CodArticolo = codArticolo,
|
|
IdxMacchina = idxMacchina,
|
|
IdxTipo = idxEvento,
|
|
InizioStato = adesso,
|
|
MatrOpr = 0,
|
|
pallet = "-",
|
|
Value = qty
|
|
};
|
|
// salva e processa
|
|
var resp = await scriviRigaEventoAsync(newRecEv);
|
|
// registro in risposta che è andato tutto bene... ovvero la qty richiesta...
|
|
answ = qty;
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processa registrazione EVENTO CONTEGGIO PEZZI x una data macchina IOB
|
|
/// </summary>
|
|
/// <param name="idxMacchina">Macchina</param>
|
|
/// <param name="qty">Pezzi da registrare</param>
|
|
/// <param name="dtEve">DataOra evento</param>
|
|
/// <param name="dtCurr">DataOra corrente</param>
|
|
/// <returns></returns>
|
|
public async Task<string> SaveCaricoPezziAsync(string idxMacchina, string qty, string dtEve = "", string dtCurr = "")
|
|
{
|
|
// default: 0, non registrato x cautela...
|
|
string answ = "0";
|
|
// Verifica se evento realtime oppure ho data specificata x processing @dtEve
|
|
DateTime adesso = DateTime.Now;
|
|
DateTime dtEvent = adesso;
|
|
bool rtimeProc = string.IsNullOrEmpty(dtEve);
|
|
if (!rtimeProc)
|
|
{
|
|
dtEvent = GetSrvDtEvent(dtEve, dtCurr);
|
|
}
|
|
// controllo per proseguire
|
|
if (!string.IsNullOrEmpty(idxMacchina) && !string.IsNullOrEmpty(qty))
|
|
{
|
|
int numPzIncr = -1;
|
|
int.TryParse(qty, out numPzIncr);
|
|
// se il conteggio è >= 0 SALVO evento...
|
|
if (numPzIncr >= 0)
|
|
{
|
|
var listOdl = await IocDbController.OdlListByMaccPeriodoAsync(idxMacchina, dtEvent, dtEvent.AddSeconds(1));
|
|
if (listOdl != null && listOdl.Count > 0)
|
|
{
|
|
string codArticolo = listOdl.FirstOrDefault()?.CodArticolo ?? "ND";
|
|
// registro evento 120 --> contapezzi in blocco !!!HARD CODED!!! !!!FIXME!!!
|
|
int idxEvento = 120;
|
|
// creo evento
|
|
EventListModel newRecEv = new EventListModel()
|
|
{
|
|
CodArticolo = codArticolo,
|
|
IdxMacchina = idxMacchina,
|
|
IdxTipo = idxEvento,
|
|
InizioStato = dtEvent,
|
|
MatrOpr = 0,
|
|
pallet = "-",
|
|
Value = qty
|
|
};
|
|
// salva e processa
|
|
var resp = await scriviRigaEventoAsync(newRecEv);
|
|
// registro in risposta che è andato tutto bene... ovvero la qty richiesta...
|
|
answ = qty;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
string errore = $"Errore: mancano parametri macchina/incremento: idxMacchina {idxMacchina} | qty {qty}";
|
|
Log.Error(errore);
|
|
answ = errore;
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processa registrazione di un counter x una data macchina IOB
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="counter">contapezzi</param>
|
|
/// <returns></returns>
|
|
public async Task<string> SaveCounterAsync(string idxMacchina, string counter)
|
|
{
|
|
string answ = "0";
|
|
// inizio processing vero e proprio INPUT...
|
|
if (string.IsNullOrEmpty(idxMacchina))
|
|
{
|
|
string errore = "Errore: parametro macchina vuoto";
|
|
Log.Info(errore);
|
|
answ = errore;
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrEmpty(counter))
|
|
{
|
|
string errore = "Errore: parametro counter vuoto";
|
|
Log.Error(errore);
|
|
answ = errore;
|
|
}
|
|
else
|
|
{
|
|
int newCounter = -1;
|
|
int.TryParse(counter, out newCounter);
|
|
// se il conteggio è >= 0 SALVO come nuovo conteggio...
|
|
if (newCounter >= 0)
|
|
{
|
|
var currKey = Utils.RedKeyPzCount(idxMacchina, MpIoNS);
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
// salvo per + tempo...
|
|
await redisDb.StringSetAsync(currKey, answ.ToString());
|
|
answ = counter;
|
|
}
|
|
else
|
|
{
|
|
int currCount = await PzCounterTcAsync(idxMacchina);
|
|
answ = currCount.ToString();
|
|
// salvo per meno tempo...
|
|
await redisDb.StringSetAsync(currKey, answ);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
public async Task<bool> SaveDataItemsAsync(string id, List<MachDataItem> dataList)
|
|
{
|
|
bool answ = false;
|
|
if (mongoController != null)
|
|
{
|
|
answ = mongoController.SaveMachineDataItems(id, dataList);
|
|
}
|
|
else
|
|
{
|
|
// modalità con SqlSb (no mongo)
|
|
if (useFactory)
|
|
{
|
|
await using var scope = _scopeFactory.CreateAsyncScope();
|
|
var mtcService = scope.ServiceProvider.GetRequiredService<IMtcSetupService>();
|
|
answ = await mtcService.ReplaceMachineDataAsync(id, dataList);
|
|
}
|
|
else
|
|
{
|
|
answ = await MtcService.ReplaceMachineDataAsync(id, dataList);
|
|
}
|
|
}
|
|
|
|
return answ;
|
|
}
|
|
|
|
public async Task<bool> SaveMachine2Iob(string idxMacchina, string serData)
|
|
{
|
|
bool fatto = false;
|
|
var currKey = Utils.RedKeyMach2Iob(idxMacchina);
|
|
// se != null --> salvo!
|
|
if (!string.IsNullOrEmpty(serData))
|
|
{
|
|
fatto = await redisDb.StringSetAsync(currKey, serData);
|
|
}
|
|
return fatto;
|
|
}
|
|
|
|
public async Task<bool> SaveMachineIobConf(string idxMacchina, Dictionary<string, string> currDict)
|
|
{
|
|
bool fatto = false;
|
|
var currKey = Utils.RedKeyMachIobConf(idxMacchina);
|
|
// se != null --> salvo!
|
|
if (currDict != null)
|
|
{
|
|
await RedisSetHashDictAsync(currKey, currDict);
|
|
fatto = true;
|
|
}
|
|
return fatto;
|
|
}
|
|
|
|
/// <summary>
|
|
/// salva il segnale di "microstato" (segnale) ASYNC
|
|
/// </summary>
|
|
/// <param name="idxMacchina">idx macchina</param>
|
|
/// <param name="valore">valOut ingresso</param>
|
|
/// <param name="dtEve">data-ora evento (server)</param>
|
|
/// <param name="contatore">contatore sequenza dati inviati</param>
|
|
/// <returns></returns>
|
|
public async Task<bool> saveSigLogAsync(string idxMacchina, string valore, DateTime dtEve, int contatore)
|
|
{
|
|
SignalLogModel newRec = new SignalLogModel()
|
|
{
|
|
IdxMacchina = idxMacchina,
|
|
DtCurr = DateTime.Now,
|
|
DtEve = dtEve,
|
|
Contatore = contatore,
|
|
Valore = valore
|
|
};
|
|
return await IocDbController.SignalLogInsertAsync(newRec);
|
|
}
|
|
|
|
/// <summary>
|
|
/// scrive un evento di keepalive sulla tabella
|
|
/// </summary>
|
|
/// <param name="IdxMacchina"></param>
|
|
/// <param name="oraMacchina"></param>
|
|
/// <returns></returns>
|
|
public async Task ScriviKeepAliveAsync(string IdxMacchina, DateTime oraMacchina)
|
|
{
|
|
// cerco se ho keep alive in redis,
|
|
var currKey = Utils.RedKeyHash($"KeepAlive:{IdxMacchina}");
|
|
bool keyPresent = await RedisKeyPresentAsync(currKey);
|
|
// se NON presente salvo in REDIS con TTL 10 sec e sul DB...
|
|
if (!keyPresent)
|
|
{
|
|
DateTime adesso = DateTime.Now;
|
|
await redisDb.StringSetAsync(currKey, adesso.ToString("s"), TimeSpan.FromSeconds(30));
|
|
// effettuo scrittura sul DB
|
|
await IocDbController.KeepAliveUpsertAsync(IdxMacchina, DateTime.Now, oraMacchina);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Salvataggio YAML completo di configurazione dell'IOB
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="iobConfFull"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> SetIobConfYamlAsync(string idxMacchina, string iobConfFull)
|
|
{
|
|
bool answ = false;
|
|
// se ho un area memoria valida...
|
|
if (!string.IsNullOrEmpty(iobConfFull))
|
|
{
|
|
// salvo!
|
|
var currKey = Utils.RedKeyIobConfYaml(idxMacchina, MpIoNS);
|
|
answ = await redisDb.StringSetAsync(currKey, iobConfFull);
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
public async Task<bool> SetIobMemMap(string idxMacchina, PlcMemMapDto currMap)
|
|
{
|
|
bool answ = false;
|
|
// se ho un area memoria valida...
|
|
if (currMap != null)
|
|
{
|
|
// salvo!
|
|
var currKey = Utils.RedKeyIobMemMap(idxMacchina, MpIoNS);
|
|
string serVal = JsonConvert.SerializeObject(currMap);
|
|
answ = await redisDb.StringSetAsync(currKey, serVal);
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP dei campi della State Machine ingressi nel formato
|
|
/// currKey: cState_nVal (current MICRO-STATE + "_" + new Value)
|
|
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE
|
|
/// </summary>
|
|
/// <param name="idxFamIn"></param>
|
|
/// <returns></returns>
|
|
public async Task<KeyValuePair<string, string>[]> StateMachInByKeyAsync(int idxFamIn)
|
|
{
|
|
// hard coded dimensione vettore DatiMacchine
|
|
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[1];
|
|
// iniziualizzo con un valOut... 0/0
|
|
answ[0] = new KeyValuePair<string, string>("0", "0");
|
|
// ORA recupero da memoria redis...
|
|
try
|
|
{
|
|
var currHash = Utils.GetHashSMI(idxFamIn);
|
|
answ = await RedisGetHashAsync(currHash);
|
|
// se è vuoto... leggo da DB e popolo!
|
|
if (answ.Length == 0)
|
|
{
|
|
answ = await resetSMIAsync(idxFamIn);
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in compilazione State Machine Ingressi x Redis:{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Statistiche ODL calcolate (da stored stp_STAT_ODL)
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public Task<List<StatODLModel>> StatOdl(int IdxOdl)
|
|
{
|
|
return SpecDbController.OdlStart(IdxOdl);
|
|
}
|
|
|
|
/// <summary>
|
|
/// restituisce il valOut da REDIS associato al tag richeisto
|
|
/// </summary>
|
|
/// <param name="redKey">Chiave in cui cercare il valOut</param>
|
|
/// <returns></returns>
|
|
public string TagConfGetKey(string redKey)
|
|
{
|
|
string outVal = "";
|
|
// cerco in REDIS la conf x l'IOB
|
|
var rawData = redisDb.StringGet(redKey);
|
|
if (!string.IsNullOrEmpty(rawData))
|
|
{
|
|
outVal = $"{rawData}";
|
|
}
|
|
return outVal;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco setup dei tag conf correnti
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public Task<Dictionary<string, List<TagData>>> TagsGetAll()
|
|
{
|
|
return Task.FromResult(currTagConf);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue traduzione dato vocabolario da Lingua + Lemma
|
|
/// </summary>
|
|
/// <param name="lemma"></param>
|
|
/// <param name="lingua"></param>
|
|
/// <returns></returns>
|
|
public string Traduci(string lemma, string lingua)
|
|
{
|
|
string answ = $"[{lemma}]";
|
|
// verifico se ho qualcosa nell'obj vocabolario...
|
|
if (ObjVocabolario == null || ObjVocabolario.Count == 0)
|
|
{
|
|
// inizializzo il vocabolario...
|
|
ObjVocabolario = VocabolarioGetAll();
|
|
}
|
|
var record = ObjVocabolario.Where(x => x.Lingua == lingua && x.Lemma == lemma).FirstOrDefault();
|
|
if (record != null)
|
|
{
|
|
answ = record.Traduzione;
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
public async Task<bool> updateDossierValue(DossierModel currDoss, FluxLogDTO editFL)
|
|
{
|
|
bool answ = false;
|
|
// recupero intero set valori dossier deserializzando...
|
|
var fluxLogList = FluxLogDtoGetByFlux(currDoss.Valore);
|
|
await Task.Delay(1);
|
|
|
|
// se tutto ok
|
|
if (fluxLogList != null)
|
|
{
|
|
// da provare...!!!!
|
|
|
|
// elimino vecchio record
|
|
var currRec = fluxLogList.FirstOrDefault(x => x.CodFlux == editFL.CodFlux && x.dtEvento == editFL.dtEvento);
|
|
if (currRec != null)
|
|
{
|
|
fluxLogList.Remove(currRec);
|
|
// aggiungo nuovo
|
|
fluxLogList.Add(editFL);
|
|
}
|
|
|
|
// serializzo nuovamente valOut
|
|
DossierFluxLogDTO? result = new DossierFluxLogDTO();
|
|
var ODLflux = result.ODL.ToList();
|
|
foreach (var item in fluxLogList)
|
|
{
|
|
ODLflux.Add(item);
|
|
}
|
|
|
|
DossierFluxLogDTO updatedResult = new DossierFluxLogDTO() { ODL = ODLflux };
|
|
|
|
string rawVal = JsonConvert.SerializeObject(updatedResult);
|
|
currDoss.Valore = rawVal;
|
|
// aggiorno record sul DB
|
|
await SpecDbController.DossiersUpdateValore(currDoss);
|
|
}
|
|
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua UPSERT elenco parametri correnti x IOB (se c'è UPDATE, se manca ADD)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="innovations"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> UpsertCurrObjItemsAsync(string idxMacchina, List<ObjItemDTO> innovations)
|
|
{
|
|
bool answ = false;
|
|
if (innovations != null)
|
|
{
|
|
Log.Info($"upsertCurrObjItems | idxMacchina: {idxMacchina} | {innovations.Count} innovations");
|
|
// leggo i valori attuali...
|
|
List<ObjItemDTO> actValues = await MachineParamListAsync(idxMacchina);
|
|
// per ogni valOut passatomi faccio insert o update rispetto elenco valori correnti in REDIS
|
|
foreach (var item in actValues)
|
|
{
|
|
// cerco nelle innovazioni SE CI SIA il valOut...
|
|
var trovato = innovations.Find(obj => obj.uid == item.uid);
|
|
// se non trovato nelle innovazioni...
|
|
if (trovato == null)
|
|
{
|
|
// lo ri-aggiungo x non perderlo
|
|
innovations.Add(item);
|
|
Log.Trace($"innovations | add | item.uid: {item.uid} | item.value: {item.value}");
|
|
}
|
|
else
|
|
// altrimenti aggiorno campo (non trasmesso) name e tengo il resto...
|
|
{
|
|
trovato.name = item.name;
|
|
Log.Info($"innovations | update | item.uid: {item.uid} | item.value: {item.value} --> {trovato.value} ");
|
|
}
|
|
}
|
|
// serializzo e salvo
|
|
string serVal = JsonConvert.SerializeObject(innovations);
|
|
|
|
var currKey = Utils.RedKeyCurrObjItems(idxMacchina, MpIoNS);
|
|
RedisValue rawData = await redisDb.StringSetAsync(currKey, serVal);
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il valore SPECIFICATO per la state machine ingressi
|
|
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE)
|
|
/// </summary>
|
|
/// <param name="idxFamIn"></param>
|
|
/// <param name="idxMicroStato"></param>
|
|
/// <param name="valoreIn"></param>
|
|
/// <returns></returns>
|
|
public async Task<string> ValoreSmiAsync(int idxFamIn, int idxMicroStato, int valoreIn)
|
|
{
|
|
string valOut = "";
|
|
var currHash = Utils.GetHashSMI(idxFamIn);
|
|
string field = $"{idxMicroStato}_{valoreIn}";
|
|
var searchVal = await RedisGetHashFieldAsync(currHash, field);
|
|
if (!searchVal.HasValue)
|
|
{
|
|
// ricarico tabella (salvando in redis x ricerca successiva)!
|
|
var valori = await StateMachInByKeyAsync(idxFamIn);
|
|
if (valori.Any(x => x.Key == field))
|
|
{
|
|
searchVal = valori.FirstOrDefault(x => x.Key == field).Value;
|
|
}
|
|
}
|
|
valOut = $"{searchVal}";
|
|
return valOut;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco completo tabella Vocabolario
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public List<VocabolarioModel> VocabolarioGetAll()
|
|
{
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
List<VocabolarioModel>? result = new List<VocabolarioModel>();
|
|
string source = "REDIS";
|
|
// cerco in redis...
|
|
RedisValue rawData = redisDb.StringGet(Utils.redisVocabolario);
|
|
if (!string.IsNullOrEmpty($"{rawData}"))
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<VocabolarioModel>>($"{rawData}");
|
|
}
|
|
else
|
|
{
|
|
result = SpecDbController.VocabolarioGetAll();
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(Utils.redisVocabolario, rawData, getRandTOut(redisLongTimeCache / 5));
|
|
source = "DB";
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"VocabolarioGetAll Read from {source}: {ts.TotalMilliseconds}ms");
|
|
if (result == null)
|
|
{
|
|
result = new List<VocabolarioModel>();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Internal Methods
|
|
|
|
/// <summary>
|
|
/// Recupera ArtNum dato CodArt (per impianti che accettano solo INT in scrittura)
|
|
/// </summary>
|
|
/// <param name="CodArt">
|
|
/// CodArt richiesto, se vuoto restituisce TUTTI i valori in tabella di decodifica
|
|
/// </param>
|
|
/// <returns>Dizionario contenente le righe delle codifiche attive Articolo/Numero</returns>
|
|
internal async Task<Dictionary<string, int>> GetArtNumAsync(string codArt)
|
|
{
|
|
Dictionary<string, int> answ = new Dictionary<string, int>();
|
|
var currData = await DecNumArtGetFiltAsync(codArt);
|
|
foreach (var item in currData)
|
|
{
|
|
answ.Add(item.CodArticolo, item.NumART);
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
#endregion Internal Methods
|
|
|
|
#region Protected Fields
|
|
|
|
protected Random rand = new Random();
|
|
|
|
#endregion Protected Fields
|
|
|
|
#region Protected Properties
|
|
|
|
protected string canCacheParametri { get; set; } = "";
|
|
|
|
#endregion Protected Properties
|
|
|
|
#region Protected Methods
|
|
|
|
/// <summary>
|
|
/// Restituisce un timeout dai minuti richiesti + tempo random 1..60 sec
|
|
/// </summary>
|
|
/// <param name="stdMinutes"></param>
|
|
/// <returns></returns>
|
|
protected TimeSpan getRandTOut(double stdMinutes)
|
|
{
|
|
double rndValue = stdMinutes + (double)rand.Next(1, 60) / 60;
|
|
return TimeSpan.FromMinutes(rndValue);
|
|
}
|
|
|
|
#endregion Protected Methods
|
|
|
|
#region Private Fields
|
|
|
|
private static IConfiguration _configuration = null!;
|
|
private static ILogger<MpDataService> _logger = null!;
|
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
|
private static IMtcSetupService MtcService = null!;
|
|
#if false
|
|
/// <summary>
|
|
/// Elenco completo valori Macchine 2 Slave
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public List<Macchine2SlaveModel> Macchine2SlaveGetAll()
|
|
{
|
|
List<Macchine2SlaveModel>? result = new List<Macchine2SlaveModel>();
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string readType = "DB";
|
|
string currKey = $"{Utils.redisBaseAddr}:M2STab";
|
|
// cerco in redis dato valore sel macchina...
|
|
RedisValue rawData = redisDb.StringGet(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<List<Macchine2SlaveModel>>($"{rawData}");
|
|
readType = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = IocDbController.Macchine2Slave();
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new List<Macchine2SlaveModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"Macchine2SlaveGetAll | Read from {readType}: {ts.TotalMilliseconds}ms");
|
|
return result;
|
|
}
|
|
#endif
|
|
private readonly IServiceScopeFactory _scopeFactory;
|
|
|
|
/// <summary>
|
|
/// Provider CultureInfo x parse valori (es dataora)
|
|
/// </summary>
|
|
private CultureInfo ciProvider = CultureInfo.InvariantCulture;
|
|
|
|
/// <summary>
|
|
/// Formato dataora standard x parsing
|
|
/// </summary>
|
|
private string dtFormat = "yyyyMMddHHmmssfff";
|
|
|
|
/// <summary>
|
|
/// Ultima esecuzione pulizia RRL x evitgare congestioni
|
|
/// </summary>
|
|
private DateTime lastCleanupRRL = DateTime.Now.AddHours(-1);
|
|
|
|
/// <summary>
|
|
/// MS max age x dato MSE
|
|
/// </summary>
|
|
private int maxAge = 2000;
|
|
|
|
private string MpIoNS = "";
|
|
|
|
/// <summary>
|
|
/// Oggetto vocabolario x uso continuo traduzione
|
|
/// </summary>
|
|
private List<VocabolarioModel> ObjVocabolario = new List<VocabolarioModel>();
|
|
|
|
/// <summary>
|
|
/// Oggetto per connessione a REDIS
|
|
/// </summary>
|
|
private ConnectionMultiplexer redisConn = null!;
|
|
|
|
/// <summary>
|
|
/// Oggetto per connessione a REDIS modalità admin (ex flux dati)
|
|
/// </summary>
|
|
private ConnectionMultiplexer redisConnAdmin = null!;
|
|
|
|
/// <summary>
|
|
/// Oggetto DB redis da impiegare x chiamate R/W
|
|
/// </summary>
|
|
private IDatabase redisDb = null!;
|
|
|
|
private int redisLongTimeCache = 5;
|
|
|
|
private int redisShortTimeCache = 2;
|
|
|
|
/// <summary>
|
|
/// Generatore random classe
|
|
/// </summary>
|
|
private Random rnd = new Random();
|
|
|
|
private bool useFactory = false;
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Private Methods
|
|
|
|
/// <summary>
|
|
/// Verifica se sia necessario inserire un cambio di stato impianto (DiarioDi Bordo) in modalità batch
|
|
/// </summary>
|
|
/// <param name="tipoInput"></param>
|
|
/// <param name="IdxMacchina"></param>
|
|
/// <param name="InizioStato"></param>
|
|
/// <param name="IdxTipo"></param>
|
|
/// <param name="CodArt"></param>
|
|
/// <param name="Value"></param>
|
|
/// <param name="MatrOpr"></param>
|
|
/// <param name="pallet"></param>
|
|
private async Task CheckCambiaStatoBatchAsync(tipoInputEvento tipoInput, string IdxMacchina, DateTime InizioStato, int IdxTipo, string CodArt, string Value, int MatrOpr, string pallet)
|
|
{
|
|
await IocDbController.CheckCambiaStatoBatchAsync(tipoInput, IdxMacchina, InizioStato, IdxTipo, CodArt, Value, MatrOpr, pallet);
|
|
#if false
|
|
List<TransizioneStatiModel> listTransit = new List<TransizioneStatiModel>();
|
|
TransizioneStatiModel? rigaTrans = null;
|
|
switch (tipoInput)
|
|
{
|
|
case tipoInputEvento.barcode:
|
|
// effettuo cambio stato INDIPENDENTEMENTE da stato precedente
|
|
listTransit = await IocDbController.SMES_getUserForcedAsync(IdxMacchina, IdxTipo);
|
|
|
|
if (listTransit.Count > 0)
|
|
{
|
|
rigaTrans = listTransit.FirstOrDefault();
|
|
// solo se cambia stato...
|
|
if (rigaTrans != null && rigaTrans.IdxStato != rigaTrans.next_IdxStato)
|
|
{
|
|
await IocDbController.DDB_InsStatoBatchAsync(IdxMacchina, InizioStato, rigaTrans.next_IdxStato, CodArt, Value, MatrOpr, pallet);
|
|
// aggiorno MSE
|
|
await IocDbController.RecalcMseAsync(IdxMacchina, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log.Debug($"Non trovata riga per: BARCODE | IdxMacchina: {IdxMacchina} | IdxTipo: {IdxTipo} | CodArt: {CodArt} | Value: {Value} | MatrOpr: {MatrOpr} | pallet: {pallet}");
|
|
}
|
|
break;
|
|
|
|
case tipoInputEvento.hw:
|
|
// verifico se ci sia necessità di cambio stato
|
|
listTransit = await IocDbController.SMES_getHwTransitionsAsync(IdxMacchina, IdxTipo);
|
|
if (listTransit.Count > 0)
|
|
{
|
|
rigaTrans = listTransit.FirstOrDefault();
|
|
if (rigaTrans != null && rigaTrans.IdxStato != rigaTrans.next_IdxStato)
|
|
{
|
|
await IocDbController.DDB_InsStatoBatchAsync(IdxMacchina, InizioStato, rigaTrans.next_IdxStato, CodArt, Value, MatrOpr, pallet);
|
|
// aggiorno MSE
|
|
await IocDbController.RecalcMseAsync(IdxMacchina, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log.Debug($"Non trovata riga per: HW | IdxMacchina: {IdxMacchina} | IdxTipo: {IdxTipo} | CodArt: {CodArt} | Value: {Value} | MatrOpr: {MatrOpr} | pallet: {pallet}");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce l'elenco codici flusso (da confFlux) x una macchina (se presenti) Impiegata
|
|
/// anche cache redis
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
private async Task<List<string>> ConfFluxMach(string idxMacchina)
|
|
{
|
|
List<string> resultList = new List<string>();
|
|
string tag = string.IsNullOrEmpty(idxMacchina) ? "ALL" : idxMacchina;
|
|
var currKey = $"{Utils.redisConfFlux}:{tag}";
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
resultList = JsonConvert.DeserializeObject<List<string>>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
var dbData = await IocDbController.ConfFluxFiltAsync(idxMacchina);
|
|
resultList = dbData
|
|
.Select(x => x.CodFlux)
|
|
.ToList();
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(resultList);
|
|
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (resultList == null)
|
|
{
|
|
resultList = new();
|
|
}
|
|
return resultList;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Svuota la cache redis x l'elenco delle righe di confFlux x una macchina (se presenti)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
private async Task<bool> DossierLastByMachResetAsync(string idxMacchina)
|
|
{
|
|
bool answ = false;
|
|
var currKey = $"{Utils.redisDossByMacLast}:{idxMacchina}";
|
|
await redisDb.KeyDeleteAsync(currKey);
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper standardizzazione valOut dataora ricevuto da IOB remoti
|
|
/// </summary>
|
|
/// <param name="s"></param>
|
|
/// <returns></returns>
|
|
private string dtFormStd(string? s)
|
|
{
|
|
return s?.Length > 17 ? s[..17] : s?.PadRight(17, '0') ?? string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce l'elenco delle data-ora di confFlux x una macchina (se presenti) Impiegata
|
|
/// anche cache redis
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="numMax">num record da recuperare</param>
|
|
/// <returns></returns>
|
|
private async Task<List<DateTime>> FluxLogFirstByMachAsync(string idxMacchina, int numMax = 10)
|
|
{
|
|
List<DateTime> resultList = new List<DateTime>();
|
|
|
|
var currKey = $"{Utils.redisFluxByMacFirst}:{idxMacchina}";
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
resultList = JsonConvert.DeserializeObject<List<DateTime>>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
var dbData = await IocDbController.FluxLogFirstByMaccAsync(idxMacchina, numMax);
|
|
resultList = dbData
|
|
.Select(x => x.dtEvento)
|
|
.ToList();
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(resultList);
|
|
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
|
|
}
|
|
if (resultList == null)
|
|
{
|
|
resultList = new List<DateTime>();
|
|
}
|
|
return resultList;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua vera chiamata x salvataggio snapshot dati FluxLog
|
|
/// </summary>
|
|
/// <param name="id"></param>
|
|
/// <param name="maxSec"></param>
|
|
/// <param name="caller"></param>
|
|
/// <returns></returns>
|
|
private async Task<string> FluxLogSaveSnapshotAsync(string id, DateTime dtStart, DateTime dtEnd, string caller)
|
|
{
|
|
string answ = "";
|
|
DateTime dataOraEvento = DateTime.Now;
|
|
Log.Debug($"{caller} | Richiesta snapshot dati FluxLog macchina: id: {id} | periodo: {dtStart} - {dtEnd}");
|
|
try
|
|
{
|
|
bool fatto = await IocDbController.FluxLogTakeSnapshotLastAsync(id, dtStart, dtEnd);
|
|
answ = fatto ? "OK" : "KO";
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in {caller}{Environment.NewLine}{exc}");
|
|
answ = "NO";
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recupero info ODL corrente da dati prod macchina
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <returns></returns>
|
|
private async Task<string> GetCurrOdlByProdAsync(string idxMacchina)
|
|
{
|
|
string answ = "";
|
|
// recupero stato...
|
|
var datiProd = await StatoProdMacchinaAsync(idxMacchina, DateTime.Now);
|
|
if (datiProd != null)
|
|
{
|
|
answ = datiProd.IdxOdl.ToString();
|
|
}
|
|
// ultimo controllo su idxOdl...
|
|
answ = answ == "" ? "0" : answ;
|
|
// restituisco!
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce il valOut booleano se la macchina sia di tipo MULTI (con più state machine x INGRESSI)
|
|
/// usando dati macchina in cache per evitare lookup ridondanti
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="datiMacc"></param>
|
|
/// <returns></returns>
|
|
private bool isMulti(string idxMacchina, Dictionary<string, string> datiMacc)
|
|
{
|
|
bool answ = false;
|
|
try
|
|
{
|
|
answ = Convert.ToBoolean(datiMacc.ContainsKey("Multi") && datiMacc["Multi"] == "1");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in isMulti{Environment.NewLine}{exc}");
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
private async Task<HashSet<string>> ListMasterAsync()
|
|
{
|
|
HashSet<string> result = new();
|
|
string currKey = $"{Utils.redisBaseAddr}:ListMaster";
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<HashSet<string>>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
var fullList = await Macchine2SlaveGetAllAsync();
|
|
result = fullList.Select(x => x.IdxMacchina).ToHashSet<string>();
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private async Task<HashSet<string>> ListSlaveAsync()
|
|
{
|
|
HashSet<string> result = new();
|
|
string currKey = $"{Utils.redisBaseAddr}:ListSlave";
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue)
|
|
{
|
|
result = JsonConvert.DeserializeObject<HashSet<string>>($"{rawData}") ?? new();
|
|
}
|
|
else
|
|
{
|
|
var fullList = await Macchine2SlaveGetAllAsync();
|
|
result = fullList.Select(x => x.IdxMacchinaSlave).Distinct().ToHashSet<string>();
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private async Task<bool> POdlFlushCache()
|
|
{
|
|
bool answ = false;
|
|
RedisValue pattern = new RedisValue($"{Utils.redisXdlData}:*");
|
|
answ = await RedisFlushPatternAsync(pattern);
|
|
pattern = new RedisValue($"{Utils.redisPOdlByOdl}:*");
|
|
answ = await RedisFlushPatternAsync(pattern);
|
|
pattern = new RedisValue($"{Utils.redisPOdlByPOdl}:*");
|
|
answ = await RedisFlushPatternAsync(pattern);
|
|
pattern = new RedisValue($"{Utils.redisPOdlList}:*");
|
|
answ = await RedisFlushPatternAsync(pattern);
|
|
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calcola l'effettivo valOut da passare alla macchina a stati INGRESSI usando dati macchina in cache
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="valore"></param>
|
|
/// <param name="datiMacc"></param>
|
|
/// <returns></returns>
|
|
private string preProcInput(string idxMacchina, string valore, Dictionary<string, string> datiMacc)
|
|
{
|
|
string newVal = "";
|
|
try
|
|
{
|
|
// variabili
|
|
int valINT = 0;
|
|
int BitFilt = 0;
|
|
int BSR = 0;
|
|
bool ExplodeBit = false;
|
|
int NumBit = 0;
|
|
int newValInt = 0;
|
|
// recupero parametri dalla cache...
|
|
int.TryParse(datiMacc.ContainsKey("BitFilt") ? datiMacc["BitFilt"] : "0", out BitFilt);
|
|
int.TryParse(datiMacc.ContainsKey("BSR") ? datiMacc["BSR"] : "0", out BSR);
|
|
Boolean.TryParse(datiMacc.ContainsKey("ExplodeBit") ? datiMacc["ExplodeBit"] : "false", out ExplodeBit);
|
|
// non usato (x ora)
|
|
int.TryParse(datiMacc.ContainsKey("NumBit") ? datiMacc["NumBit"] : "0", out NumBit);
|
|
|
|
// recupero valOut
|
|
valINT = int.Parse(valore, NumberStyles.HexNumber);
|
|
// filtro
|
|
newValInt = MP.Core.Utils.bMaskInt(valINT, BitFilt);
|
|
// effettuo eventuale BitShiftRight
|
|
if (BSR > 0)
|
|
{
|
|
newValInt = newValInt >> BSR;
|
|
}
|
|
// effettuo eventuale esplosione in BIT esclusivi
|
|
if (ExplodeBit)
|
|
{
|
|
newValInt = Convert.ToInt32(1 << newValInt);
|
|
}
|
|
// riconverto a STRING HEX!!!
|
|
newVal = newValInt.ToString("X");
|
|
}
|
|
catch
|
|
{
|
|
newVal = valore;
|
|
}
|
|
|
|
return newVal;
|
|
}
|
|
|
|
private async Task resetCacheArticoli()
|
|
{
|
|
RedisValue pattern = new RedisValue($"{Utils.redisArtByDossier}:*");
|
|
await RedisFlushPatternAsync(pattern);
|
|
pattern = new RedisValue($"{Utils.redisArtList}:*");
|
|
await RedisFlushPatternAsync(pattern);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice elenco KVP dei campi DatiMacchine + StatoMacchine per l'impianto indicato
|
|
/// </summary>
|
|
/// <param name="idxMacc"></param>
|
|
/// <returns></returns>
|
|
private async Task<Dictionary<string, string>> ResetDatiMacchinaAsync(string idxMacc)
|
|
{
|
|
Dictionary<string, string> result = new Dictionary<string, string>();
|
|
VMSFDModel? dbResult = null;
|
|
if (useFactory)
|
|
{
|
|
await using var scope = _scopeFactory.CreateAsyncScope();
|
|
var mtcService = scope.ServiceProvider.GetRequiredService<MpIocController>();
|
|
dbResult = await mtcService.VMSFDGetByMaccAsync(idxMacc);
|
|
}
|
|
else
|
|
{
|
|
dbResult = await IocDbController.VMSFDGetByMaccAsync(idxMacc);
|
|
}
|
|
|
|
if (dbResult == null) return new Dictionary<string, string>();
|
|
|
|
double numSecCache = redisLongTimeCache;
|
|
// converto in formato dizionario...
|
|
if (dbResult != null)
|
|
{
|
|
// salvo 1:1 i valori... STATO
|
|
result.Add("IdxMicroStato", $"{dbResult.IdxMicroStato}");
|
|
result.Add("IdxStato", $"{dbResult.IdxStato}");
|
|
result.Add("CodArticolo", $"{dbResult.CodArticolo}");
|
|
result.Add("insEnabled", $"{dbResult.InsEnabled}");
|
|
result.Add("sLogEnabled", $"{dbResult.SLogEnabled}");
|
|
result.Add("pallet", $"{dbResult.Pallet}");
|
|
result.Add("CodArticolo_A", $"{dbResult.CodArticoloA}");
|
|
result.Add("CodArticolo_B", $"{dbResult.CodArticoloB}");
|
|
result.Add("TempoCicloBase", $"{dbResult.TempoCicloBase}");
|
|
result.Add("PzPalletProd", $"{dbResult.PzPalletProd}");
|
|
result.Add("MatrOpr", $"{dbResult.MatrOpr}");
|
|
result.Add("lastVal", $"{dbResult.LastVal}");
|
|
result.Add("TCBase", $"{dbResult.TempoCicloBase}");
|
|
|
|
//...e SETUP
|
|
result.Add("CodMacc", $"{dbResult.Codmacchina}");
|
|
result.Add("IdxFamIn", $"{dbResult.IdxFamigliaIngresso}");
|
|
result.Add("Multi", $"{dbResult.Multi}");
|
|
result.Add("BitFilt", $"{dbResult.BitFilt}");
|
|
result.Add("MaxVal", $"{dbResult.MaxVal}");
|
|
result.Add("BSR", $"{dbResult.Bsr}");
|
|
result.Add("ExplodeBit", $"{dbResult.ExplodeBit}");
|
|
result.Add("NumBit", $"{dbResult.NumBit}");
|
|
result.Add("IdxFamMacc", $"{dbResult.IdxFamiglia}");
|
|
result.Add("simplePallet", $"{dbResult.SimplePallet}");
|
|
result.Add("palletChange", $"{dbResult.PalletChange}");
|
|
// durata cache in secondi dal valOut insEnabled...
|
|
//double numSecCache = ((result["insEnabled"].ToLower() == "true") ? redisShortTimeCache : redisLongTimeCache);
|
|
numSecCache = dbResult.InsEnabled ? redisShortTimeCache : redisLongTimeCache;
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
}
|
|
// dati master/slave
|
|
string isMaster = (await ListMasterAsync()).Contains(idxMacc) ? "1" : "0";
|
|
string isSlave = (await ListSlaveAsync()).Contains(idxMacc) ? "1" : "0";
|
|
result.Add("Master", isMaster);
|
|
result.Add("Slave", isSlave);
|
|
|
|
// Processing redis in transazoine...
|
|
var redKey = Utils.RedKeyDatiMacc(idxMacc, MpIoNS);
|
|
|
|
// variazione con redis transaction...
|
|
var transaction = redisDb.CreateTransaction();
|
|
// 1. Eliminiamo la chiave (rimuove i vecchi campi)
|
|
_ = transaction.KeyDeleteAsync(redKey);
|
|
// 2. Prepariamo gli HashEntry per il batch (più efficiente di un Dictionary)
|
|
HashEntry[] entries = result.Select(kvp => new HashEntry(kvp.Key, kvp.Value)).ToArray();
|
|
// 3. Inseriamo i nuovi valori
|
|
_ = transaction.HashSetAsync(redKey, entries);
|
|
// 4. Impostiamo l'expiration in un unico colpo
|
|
_ = transaction.KeyExpireAsync(redKey, TimeSpan.FromSeconds(numSecCache));
|
|
// Eseguiamo tutto in un unico viaggio verso Redis
|
|
bool success = await transaction.ExecuteAsync();
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resetta (rileggendo) i dati della State Machine ingressi nel formato
|
|
/// currKey: cState_nVal (current MICRO-STATE + "_" + new Value)
|
|
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE)
|
|
/// </summary>
|
|
/// <param name="idxFamIn"></param>
|
|
/// <returns></returns>
|
|
private async Task<KeyValuePair<string, string>[]> resetSMIAsync(int idxFamIn)
|
|
{
|
|
var currHash = Utils.GetHashSMI(idxFamIn);
|
|
// leggo da DB...
|
|
var tabSMI = await IocDbController.StateMachineIngressiAsync(idxFamIn);
|
|
|
|
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[tabSMI.Count];
|
|
// salvo tutti i valori StateMachineIngressi...
|
|
int i = 0;
|
|
string key = "";
|
|
string val = "";
|
|
foreach (var item in tabSMI)
|
|
{
|
|
key = string.Format("{0}_{1}", item.IdxMicroStato, item.ValoreIngresso);
|
|
val = string.Format("{0}_{1}", item.IdxTipoEvento, item.NextIdxMicroStato);
|
|
answ[i] = new KeyValuePair<string, string>(key, val);
|
|
i++;
|
|
}
|
|
// verifico il timeout (default 60 sec...)
|
|
int tOut = 300;
|
|
var sTOutSmi = await tryGetConfigAsync("TmOut.SMI");
|
|
if (!string.IsNullOrEmpty(sTOutSmi))
|
|
{
|
|
int.TryParse(sTOutSmi, out tOut);
|
|
}
|
|
// salvo in redis!
|
|
await RedisSetHashAsync(currHash, answ, tOut);
|
|
return answ;
|
|
}
|
|
|
|
#if false
|
|
/// <summary>
|
|
/// Scrive una riga di evento nel db + check cambio stato DiarioDiBordo
|
|
/// </summary>
|
|
/// <param name="newRec">codice macchina</param>
|
|
/// <returns></returns>
|
|
private inputComandoMapo scriviRigaEvento(EventListModel newRec)
|
|
{
|
|
bool inserito = false;
|
|
try
|
|
{
|
|
// inserisco evento
|
|
inserito = IocDbController.EvListInsert(newRec);
|
|
// faccio controllo per eventuale cambio stato da tab transizioni...
|
|
CheckCambiaStatoBatchAsync(tipoInputEvento.hw, newRec.IdxMacchina, newRec.InizioStato ?? DateTime.Now, newRec.IdxTipo, newRec.CodArticolo, newRec.Value, newRec.MatrOpr, newRec.pallet);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in scriviRigaEvento | IdxMacchina {newRec.IdxMacchina} | IdxTipo {newRec.IdxTipo} | codArticolo {newRec.CodArticolo} | Value {newRec.Value} | MatrOpr {newRec.MatrOpr} | Pallet {newRec.pallet} | dTime {newRec.InizioStato}{Environment.NewLine}{exc}");
|
|
}
|
|
// formatto output
|
|
inputComandoMapo answ = new inputComandoMapo();
|
|
answ.outValue = inserito.ToString();
|
|
answ.needStatusRefresh = true;
|
|
return answ;
|
|
}
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Scrive una riga di evento nel db + check cambio stato DiarioDiBordo
|
|
/// </summary>
|
|
/// <param name="newRec">codice macchina</param>
|
|
/// <returns></returns>
|
|
private async Task<inputComandoMapo> scriviRigaEventoAsync(EventListModel newRec)
|
|
{
|
|
bool inserito = false;
|
|
try
|
|
{
|
|
// inserisco evento
|
|
inserito = await IocDbController.EvListInsertAsync(newRec);
|
|
// faccio controllo per eventuale cambio stato da tab transizioni...
|
|
await CheckCambiaStatoBatchAsync(tipoInputEvento.hw, newRec.IdxMacchina, newRec.InizioStato ?? DateTime.Now, newRec.IdxTipo, newRec.CodArticolo, newRec.Value, newRec.MatrOpr, newRec.pallet);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in scriviRigaEvento | IdxMacchina {newRec.IdxMacchina} | IdxTipo {newRec.IdxTipo} | codArticolo {newRec.CodArticolo} | Value {newRec.Value} | MatrOpr {newRec.MatrOpr} | Pallet {newRec.pallet} | dTime {newRec.InizioStato}{Environment.NewLine}{exc}");
|
|
}
|
|
// formatto output
|
|
inputComandoMapo answ = new inputComandoMapo();
|
|
answ.outValue = inserito.ToString();
|
|
answ.needStatusRefresh = true;
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scrive una riga evento + una riga microstato insieme, ed effettua verifica necessità cambio stato
|
|
/// </summary>
|
|
/// <param name="newRecMsm">Record MicroStatoMacchina</param>
|
|
/// <param name="newRecEv">record EventList</param>
|
|
/// <returns></returns>
|
|
private async Task<inputComandoMapo> scriviRigaEventoAsync(MicroStatoMacchinaModel newRecMsm, EventListModel newRecEv)
|
|
{
|
|
bool inserito = false;
|
|
if (useFactory)
|
|
{
|
|
await using var scope = _scopeFactory.CreateAsyncScope();
|
|
var iocService = scope.ServiceProvider.GetRequiredService<IIocService>();
|
|
|
|
// inserisco evento
|
|
inserito = await iocService.EvListMicroStatoInsertAsync(newRecMsm, newRecEv);
|
|
// faccio controllo per eventuale cambio stato da tab transizioni...
|
|
|
|
await iocService.CheckCambiaStatoBatchAsync(tipoInputEvento.hw, newRecEv.IdxMacchina, newRecEv.InizioStato ?? DateTime.Now, newRecEv.IdxTipo, newRecEv.CodArticolo, newRecEv.Value, newRecEv.MatrOpr, newRecEv.pallet);
|
|
}
|
|
else
|
|
{
|
|
|
|
try
|
|
{
|
|
// inserisco evento
|
|
inserito = await IocDbController.EvListMicroStatoInsertAsync(newRecMsm, newRecEv);
|
|
// faccio controllo per eventuale cambio stato da tab transizioni...
|
|
await CheckCambiaStatoBatchAsync(tipoInputEvento.hw, newRecEv.IdxMacchina, newRecEv.InizioStato ?? DateTime.Now, newRecEv.IdxTipo, newRecEv.CodArticolo, newRecEv.Value, newRecEv.MatrOpr, newRecEv.pallet);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in scriviRigaEvento | IdxMacchina {newRecEv.IdxMacchina} | IdxTipo {newRecEv.IdxTipo} | codArticolo {newRecEv.CodArticolo} | Value {newRecEv.Value} | MatrOpr {newRecEv.MatrOpr} | Pallet {newRecEv.pallet} | dTime {newRecEv.InizioStato}{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
// formatto output
|
|
inputComandoMapo answ = new inputComandoMapo();
|
|
answ.outValue = inserito.ToString();
|
|
answ.needStatusRefresh = true;
|
|
return answ;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Scrive una riga di evento manuale (barcode) nel db + check cambio stato DiarioDiBordo
|
|
/// </summary>
|
|
/// <param name="newRec">codice macchina</param>
|
|
/// <returns></returns>
|
|
private async Task<inputComandoMapo> scriviRigaEventoBarcodeAsync(EventListModel newRec)
|
|
{
|
|
bool inserito = false;
|
|
try
|
|
{
|
|
// inserisco evento
|
|
inserito = await IocDbController.EvListInsertAsync(newRec);
|
|
// faccio controllo per eventuale cambio stato da tab transizioni...
|
|
await CheckCambiaStatoBatchAsync(tipoInputEvento.barcode, newRec.IdxMacchina, newRec.InizioStato ?? DateTime.Now, newRec.IdxTipo, newRec.CodArticolo, newRec.Value, newRec.MatrOpr, newRec.pallet);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in scriviRigaEvento | IdxMacchina {newRec.IdxMacchina} | IdxTipo {newRec.IdxTipo} | codArticolo {newRec.CodArticolo} | Value {newRec.Value} | MatrOpr {newRec.MatrOpr} | Pallet {newRec.pallet} | dTime {newRec.InizioStato}{Environment.NewLine}{exc}");
|
|
}
|
|
// formatto output
|
|
inputComandoMapo answ = new inputComandoMapo();
|
|
answ.outValue = inserito.ToString();
|
|
answ.needStatusRefresh = true;
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stato prod macchina (completo)
|
|
/// </summary>
|
|
/// <param name="idxMacchina"></param>
|
|
/// <param name="dtReq"></param>
|
|
/// <returns></returns>
|
|
private async Task<StatoProdModel> StatoProdMacchinaAsync(string idxMacchina, DateTime dtReq, bool forceDb = false)
|
|
{
|
|
// setup parametri costanti
|
|
string source = "DB";
|
|
StatoProdModel? result = new StatoProdModel();
|
|
// cerco in _redisConn...
|
|
string currKey = $"{Utils.redisStatoProd}:{idxMacchina}:{dtReq:HHmm}";
|
|
RedisValue rawData = await redisDb.StringGetAsync(currKey);
|
|
if (rawData.HasValue && !forceDb)
|
|
{
|
|
result = JsonConvert.DeserializeObject<StatoProdModel>($"{rawData}");
|
|
source = "REDIS";
|
|
}
|
|
else
|
|
{
|
|
result = await IocDbController.StatoProdMacchinaAsync(idxMacchina, dtReq);
|
|
// serializzo e salvo...
|
|
rawData = JsonConvert.SerializeObject(result);
|
|
await redisDb.StringSetAsync(currKey, rawData, TimeSpan.FromSeconds(60));
|
|
}
|
|
if (result == null)
|
|
{
|
|
result = new StatoProdModel();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce valOut della stringa (SE disponibile)
|
|
/// </summary>
|
|
/// <param name="keyName"></param>
|
|
/// <returns></returns>
|
|
private async Task<string> tryGetConfigAsync(string keyName)
|
|
{
|
|
string answ = "";
|
|
// preselezione valori
|
|
var configData = await ConfigGetAllAsync();
|
|
var currRec = configData.FirstOrDefault(x => x.Chiave == keyName);
|
|
if (currRec != null)
|
|
{
|
|
answ = currRec.Valore;
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
#if false
|
|
/// <summary>
|
|
/// Restituisce il valOut SPECIFICATO per la state machine ingressi
|
|
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE)
|
|
/// </summary>
|
|
/// <param name="idxFamIn"></param>
|
|
/// <param name="idxMicroStato"></param>
|
|
/// <param name="valoreIn"></param>
|
|
/// <returns></returns>
|
|
private string valoreSMI(int idxFamIn, int idxMicroStato, int valoreIn)
|
|
{
|
|
var currHash = Utils.GetHashSMI(idxFamIn);
|
|
string field = string.Format("{0}_{1}", idxMicroStato, valoreIn);
|
|
return RedisGetHashFieldAsync(currHash, field);
|
|
}
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// cerca codice in anagrafica macchine ed eventualmente inserisce nuova macchina
|
|
/// </summary>
|
|
/// <param name="IdxMacchina"></param>
|
|
private async Task verificaIdxMacchinaAsync(string IdxMacchina)
|
|
{
|
|
bool needDB = false;
|
|
try
|
|
{
|
|
// esecuzione in REDIS...cerco status macchina...
|
|
if ((await mDatiMacchineAsync(IdxMacchina)).Count == 0)
|
|
{
|
|
needDB = true;
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
if (needDB)
|
|
{
|
|
// verifico se esiste su DB
|
|
var dbRec = await IocDbController.MacchineGetByIdxAsync(IdxMacchina);
|
|
if (dbRec == null)
|
|
{
|
|
MacchineModel newRec = new MacchineModel()
|
|
{
|
|
IdxMacchina = IdxMacchina,
|
|
CodMacchina = "0000",
|
|
Nome = IdxMacchina,
|
|
Descrizione = "Macchina non codificata",
|
|
Note = "-",
|
|
locazione = "",
|
|
RecipeArchivePath = "",
|
|
RecipePath = ""
|
|
};
|
|
await IocDbController.MacchineUpsertAsync(newRec);
|
|
|
|
// verifico ci sia un microstato macchina...
|
|
var recMSM = await IocDbController.MicroStatoMacchinaGetByIdxMaccAsync(IdxMacchina);
|
|
if (recMSM.Count == 0)
|
|
{
|
|
// inserisco nuovo stato...
|
|
MicroStatoMacchinaModel msRec = new MicroStatoMacchinaModel()
|
|
{
|
|
IdxMacchina = IdxMacchina,
|
|
IdxMicroStato = 0,
|
|
InizioStato = DateTime.Now,
|
|
Value = "00"
|
|
};
|
|
await IocDbController.MicroStatoMacchinaUpsertAsync(msRec);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion Private Methods
|
|
}
|
|
} |