Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f738c0a690 | |||
| 5e7016629a | |||
| 12994c5c7a | |||
| 1ff5b10a8f | |||
| 3c42f0ab83 | |||
| 295dab2fd9 | |||
| c8632f00d5 | |||
| 1231731c8f | |||
| 650d88a276 | |||
| c03a8a7827 | |||
| 6c400332ff | |||
| 56392e0dcf | |||
| f192c35454 | |||
| 6105e76917 | |||
| 3c0eb3fb46 | |||
| e9c4049824 | |||
| 1361aab3b9 | |||
| db44a8ca87 | |||
| 1d1a71e95f | |||
| 850c549b1b | |||
| 9f6e012b51 | |||
| 1e7572a098 | |||
| 2594166efc | |||
| d17e394416 | |||
| 2169da5ec3 | |||
| 5175af0769 | |||
| 6a7a66dfc5 | |||
| 063018f9ad | |||
| 3989fa5659 | |||
| 61b590d4fa | |||
| 5e21535103 | |||
| 89529d9018 | |||
| 06baf0167c | |||
| d447b5501f | |||
| bd583a59fe | |||
| 054e5fe72e | |||
| 081b52cfa8 | |||
| e28d620814 | |||
| 7a2eab03f4 | |||
| b4b7d21592 | |||
| 26ca34f99a | |||
| db7372b10a | |||
| bbaca1adc5 | |||
| 657e203767 | |||
| 1eaedba6cd | |||
| e6df6a5e18 | |||
| 3499d8b32d | |||
| 10e39b1c32 | |||
| a6900f01a1 | |||
| d4615d9ef2 | |||
| fa467778e5 | |||
| 7c9406682c | |||
| 4d2ae932d0 | |||
| ed4d5f4743 | |||
| bbdf6b4012 | |||
| 3a3336fcdf |
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<Version>8.16.2606.408</Version>
|
<Version>8.16.2606.1117</Version>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<RootNamespace>MP_TAB3</RootNamespace>
|
<RootNamespace>MP_TAB3</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<i>Modulo MAPOSPEC </i>
|
<i>Modulo MAPOSPEC </i>
|
||||||
<h4>Versione: 8.16.2606.408</h4>
|
<h4>Versione: 8.16.2606.1117</h4>
|
||||||
<br /> Note di rilascio:
|
<br /> Note di rilascio:
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
8.16.2606.408
|
8.16.2606.1117
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<item>
|
<item>
|
||||||
<version>8.16.2606.408</version>
|
<version>8.16.2606.1117</version>
|
||||||
<url>https://nexus.steamware.net/repository/SWS/MP-TAB3/stable/LAST/MP-TAB3.zip</url>
|
<url>https://nexus.steamware.net/repository/SWS/MP-TAB3/stable/LAST/MP-TAB3.zip</url>
|
||||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-TAB3/stable/LAST/ChangeLog.html</changelog>
|
<changelog>https://nexus.steamware.net/repository/SWS/MP-TAB3/stable/LAST/ChangeLog.html</changelog>
|
||||||
<mandatory>false</mandatory>
|
<mandatory>false</mandatory>
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ namespace MP.Data.Controllers
|
|||||||
{
|
{
|
||||||
public class MpIocController
|
public class MpIocController
|
||||||
{
|
{
|
||||||
protected readonly IDbContextFactory<MoonProContext> _ctxFactory;
|
|
||||||
protected readonly IDbContextFactory<MoonPro_FluxContext> _ctxFactoryFL;
|
|
||||||
#region Public Constructors
|
#region Public Constructors
|
||||||
|
|
||||||
public MpIocController(
|
public MpIocController(
|
||||||
@@ -24,21 +22,8 @@ namespace MP.Data.Controllers
|
|||||||
IDbContextFactory<MoonProContext> ctxFactory,
|
IDbContextFactory<MoonProContext> ctxFactory,
|
||||||
IDbContextFactory<MoonPro_FluxContext> ctxFactoryFL)
|
IDbContextFactory<MoonPro_FluxContext> ctxFactoryFL)
|
||||||
{
|
{
|
||||||
#if false
|
|
||||||
_configuration = configuration;
|
|
||||||
#endif
|
|
||||||
_ctxFactory = ctxFactory;
|
_ctxFactory = ctxFactory;
|
||||||
_ctxFactoryFL = ctxFactoryFL;
|
_ctxFactoryFL = ctxFactoryFL;
|
||||||
#if false
|
|
||||||
string connStr = configuration.GetConnectionString("MP.Data");
|
|
||||||
options = new DbContextOptionsBuilder<MoonProContext>()
|
|
||||||
.UseSqlServer(connStr)
|
|
||||||
.Options;
|
|
||||||
string connStrFlux = configuration.GetConnectionString("MP.Flux");
|
|
||||||
optionsFlux = new DbContextOptionsBuilder<MoonPro_FluxContext>()
|
|
||||||
.UseSqlServer(connStrFlux)
|
|
||||||
.Options;
|
|
||||||
#endif
|
|
||||||
Log.Info("Avviata classe MpIocController");
|
Log.Info("Avviata classe MpIocController");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,9 +485,6 @@ namespace MP.Data.Controllers
|
|||||||
|
|
||||||
// Update() allega l'entità e segna tutti i campi come Modified
|
// Update() allega l'entità e segna tutti i campi come Modified
|
||||||
dbCtx.DbSetMicroStatoMacc.Update(actRec);
|
dbCtx.DbSetMicroStatoMacc.Update(actRec);
|
||||||
#if false
|
|
||||||
dbCtx.Entry(actRec).State = EntityState.Modified;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ora record EVList
|
// ora record EVList
|
||||||
@@ -540,28 +522,6 @@ namespace MP.Data.Controllers
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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>> FluxLogGetLastFiltAsync(DateTime DtMax, DateTime DtMin, string IdxMacchina, string CodFlux, int MaxRec)
|
|
||||||
{
|
|
||||||
using var dbCtx = await _ctxFactoryFL.CreateDbContextAsync();
|
|
||||||
|
|
||||||
return await dbCtx
|
|
||||||
.DbSetFluxLog
|
|
||||||
.AsNoTracking()
|
|
||||||
.Where(x => (x.dtEvento >= DtMin && x.dtEvento <= DtMax) && (IdxMacchina == "*" || x.IdxMacchina == IdxMacchina) && (CodFlux == "*" || x.CodFlux == CodFlux))
|
|
||||||
.OrderByDescending(x => x.dtEvento)
|
|
||||||
.Take(MaxRec)
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Aggiunta record FluxLog
|
/// Aggiunta record FluxLog
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -574,8 +534,7 @@ namespace MP.Data.Controllers
|
|||||||
var currRec = dbCtx
|
var currRec = dbCtx
|
||||||
.DbSetFluxLog
|
.DbSetFluxLog
|
||||||
.Add(newRec);
|
.Add(newRec);
|
||||||
return await dbCtx.SaveChangesAsync()>0;
|
return await dbCtx.SaveChangesAsync() > 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -597,266 +556,6 @@ namespace MP.Data.Controllers
|
|||||||
return result > 0;
|
return result > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Upsert record keepalive
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="IdxMacc"></param>
|
|
||||||
/// <param name="OraServer"></param>
|
|
||||||
/// <param name="OraMacc"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<bool> KeepAliveUpsertAsync(string IdxMacc, DateTime OraServer, DateTime OraMacc)
|
|
||||||
{
|
|
||||||
bool fatto = false;
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var currRec = await dbCtx
|
|
||||||
.DbSetKeepAlive
|
|
||||||
.Where(x => x.IdxMacchina == IdxMacc)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
if (currRec != null)
|
|
||||||
{
|
|
||||||
currRec.DataOraServer = OraServer;
|
|
||||||
currRec.DataOraMacchina = OraMacc;
|
|
||||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
KeepAliveModel newRec = new KeepAliveModel()
|
|
||||||
{
|
|
||||||
IdxMacchina = IdxMacc,
|
|
||||||
DataOraMacchina = OraMacc,
|
|
||||||
DataOraServer = OraServer,
|
|
||||||
DataOraStart = DateTime.Now
|
|
||||||
};
|
|
||||||
dbCtx
|
|
||||||
.DbSetKeepAlive
|
|
||||||
.Add(newRec);
|
|
||||||
}
|
|
||||||
fatto = await dbCtx.SaveChangesAsync() > 0;
|
|
||||||
|
|
||||||
return fatto;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<LinkMenuModel>> ListLinkFiltAsync(string tipoLink)
|
|
||||||
{
|
|
||||||
List<LinkMenuModel> dbResult = new List<LinkMenuModel>();
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
dbResult = await dbCtx
|
|
||||||
.DbSetLinkMenu
|
|
||||||
.Where(x => x.TipoLink == tipoLink)
|
|
||||||
.AsNoTracking()
|
|
||||||
.OrderBy(x => x.Ordine)
|
|
||||||
.ToListAsync();
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Elenco valori ammessi x tabella/colonna con filtro parametrico
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tabName">Filtro tabella (se "" tutto)</param>
|
|
||||||
/// <param name="fieldName">Filtro colonna (se "" tutto)</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<ListValuesModel>> ListValuesFiltAsync(string tabName, string fieldName)
|
|
||||||
{
|
|
||||||
List<ListValuesModel> dbResult = new List<ListValuesModel>();
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var query = dbCtx
|
|
||||||
.DbSetListValues
|
|
||||||
.AsNoTracking()
|
|
||||||
.AsQueryable();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(tabName))
|
|
||||||
query = query.Where(x => x.TableName == tabName);
|
|
||||||
if (!string.IsNullOrEmpty(fieldName))
|
|
||||||
query = query.Where(x => x.FieldName == fieldName);
|
|
||||||
|
|
||||||
dbResult = await query.ToListAsync();
|
|
||||||
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Intera tabella relazione master/slave in machine (gestione setup master - slave)
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<Macchine2SlaveModel>> Macchine2SlaveAsync()
|
|
||||||
{
|
|
||||||
List<Macchine2SlaveModel> dbResult = new List<Macchine2SlaveModel>();
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
dbResult = await dbCtx
|
|
||||||
.DbSetM2S
|
|
||||||
.AsNoTracking()
|
|
||||||
.OrderBy(x => x.IdxMacchina)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Elenco Record Macchine
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<MacchineModel>> MacchineGetAllAsync()
|
|
||||||
{
|
|
||||||
List<MacchineModel> dbResult = new List<MacchineModel>();
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
dbResult = await dbCtx
|
|
||||||
.DbSetMacchine
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<MacchineModel?> MacchineGetByIdxAsync(string IdxMacchina)
|
|
||||||
{
|
|
||||||
MacchineModel dbResult = null;
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
dbResult = await dbCtx
|
|
||||||
.DbSetMacchine
|
|
||||||
.FirstOrDefaultAsync(x => x.IdxMacchina == IdxMacchina);
|
|
||||||
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Elenco da tabella Macchine
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="codGruppo"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<MacchineModel>> MacchineGetFiltAsync(string codGruppo)
|
|
||||||
{
|
|
||||||
List<MacchineModel> dbResult = new List<MacchineModel>();
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
if (codGruppo == "*")
|
|
||||||
{
|
|
||||||
dbResult = await dbCtx
|
|
||||||
.DbSetMacchine
|
|
||||||
.AsNoTracking()
|
|
||||||
.OrderBy(x => x.IdxMacchina)
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dbResult = await dbCtx
|
|
||||||
.DbSetGrp2Macc
|
|
||||||
.Where(g => g.CodGruppo == codGruppo)
|
|
||||||
.Join(dbCtx.DbSetMacchine,
|
|
||||||
g => g.IdxMacchina,
|
|
||||||
m => m.IdxMacchina,
|
|
||||||
(g, m) => m
|
|
||||||
)
|
|
||||||
.AsNoTracking()
|
|
||||||
.OrderBy(x => x.IdxMacchina)
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Upsert Record Macchine ASYNC
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<bool> MacchineUpsertAsync(MacchineModel entity)
|
|
||||||
{
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
// Recuperiamo l'entità tracciata dal context
|
|
||||||
var trackedEntity = await dbCtx
|
|
||||||
.DbSetMacchine
|
|
||||||
.FirstOrDefaultAsync(x => x.IdxMacchina == entity.IdxMacchina);
|
|
||||||
|
|
||||||
if (trackedEntity != null)
|
|
||||||
{
|
|
||||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
|
||||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dbCtx.DbSetMacchine.Update(entity);
|
|
||||||
}
|
|
||||||
bool fatto = await dbCtx.SaveChangesAsync() > 0;
|
|
||||||
return fatto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Elenco da tabella Macchine
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="IdxMacc"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<MicroStatoMacchinaModel>> MicroStatoMacchinaGetByIdxMaccAsync(string IdxMacc)
|
|
||||||
{
|
|
||||||
List<MicroStatoMacchinaModel> dbResult = new List<MicroStatoMacchinaModel>();
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
dbResult = await dbCtx
|
|
||||||
.DbSetMicroStatoMacc
|
|
||||||
.Where(x => x.IdxMacchina == IdxMacc)
|
|
||||||
.AsNoTracking()
|
|
||||||
.ToListAsync();
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Aggiornamento record Microstato macchina
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="newRec"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<bool> MicroStatoMacchinaUpsertAsync(MicroStatoMacchinaModel newRec)
|
|
||||||
{
|
|
||||||
bool fatto = false;
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var actRec = await dbCtx
|
|
||||||
.DbSetMicroStatoMacc
|
|
||||||
.Where(x => x.IdxMacchina == newRec.IdxMacchina)
|
|
||||||
.AsNoTracking()
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
if (actRec == null)
|
|
||||||
{
|
|
||||||
dbCtx
|
|
||||||
.DbSetMicroStatoMacc
|
|
||||||
.Add(newRec);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
actRec.IdxMicroStato = newRec.IdxMicroStato;
|
|
||||||
actRec.InizioStato = newRec.InizioStato;
|
|
||||||
actRec.Value = newRec.Value;
|
|
||||||
|
|
||||||
dbCtx.Entry(actRec).State = EntityState.Modified;
|
|
||||||
}
|
|
||||||
fatto = await dbCtx.SaveChangesAsync() > 0;
|
|
||||||
|
|
||||||
return fatto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Elenco da tabella MappaStatoExplModel
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<MappaStatoExplModel>> MseGetAllAsync(int maxAge = 2000)
|
|
||||||
{
|
|
||||||
List<MappaStatoExplModel> dbResult = new List<MappaStatoExplModel>();
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var maxAgeSec = new SqlParameter("@maxAgeSec", maxAge);
|
|
||||||
|
|
||||||
dbResult = await dbCtx
|
|
||||||
.DbSetMSE
|
|
||||||
.FromSqlRaw("EXEC stp_MSE_getData @maxAgeSec", maxAgeSec)
|
|
||||||
.AsNoTracking()
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generazione automatica ODL
|
/// Generazione automatica ODL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -929,28 +628,6 @@ namespace MP.Data.Controllers
|
|||||||
return answ;
|
return answ;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fix ODL per macchine SLAVE
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idxMacchina"></param>
|
|
||||||
/// <param name="numDayPrev"></param>
|
|
||||||
/// <param name="doInsert"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<bool> OdlFixMachineSlave(string idxMacchina, int numDayPrev, int doInsert)
|
|
||||||
{
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var idxMaccParam = new SqlParameter("@IdxMacchina", idxMacchina ?? "");
|
|
||||||
var numDayPrevParam = new SqlParameter("@NumDayPrev", numDayPrev);
|
|
||||||
var doInsertParam = new SqlParameter("@DoInsert", doInsert);
|
|
||||||
|
|
||||||
var result = await dbCtx
|
|
||||||
.Database
|
|
||||||
.ExecuteSqlRawAsync("EXEC stp_ODL_fixMachineSlave @IdxMacchina, @NumDayPrev, @DoInsert", idxMaccParam, numDayPrevParam, doInsertParam);
|
|
||||||
|
|
||||||
return result != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fix ODL per macchine SLAVE Async
|
/// Fix ODL per macchine SLAVE Async
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -993,30 +670,6 @@ namespace MP.Data.Controllers
|
|||||||
return answ;
|
return answ;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Elenco ODL data macchina e periodo
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idxMacchina"></param>
|
|
||||||
/// <param name="dtStart"></param>
|
|
||||||
/// <param name="dtEnd"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<ODLExpModel>> OdlListByMaccPeriodoAsync(string idxMacchina, DateTime dtStart, DateTime dtEnd)
|
|
||||||
{
|
|
||||||
List<ODLExpModel> dbResult = new List<ODLExpModel>();
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacchina);
|
|
||||||
var DataFrom = new SqlParameter("@dataFrom", dtStart);
|
|
||||||
var DataTo = new SqlParameter("@dataTo", dtEnd);
|
|
||||||
dbResult = await dbCtx
|
|
||||||
.DbSetODLExp
|
|
||||||
.FromSqlRaw("EXEC stp_ODL_getByMacchinaPeriodo @IdxMacchina, @dataFrom, @dataTo", IdxMacchina, DataFrom, DataTo)
|
|
||||||
.AsNoTracking()
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Conteggio PzProd Macchina Async
|
/// Conteggio PzProd Macchina Async
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1131,27 +784,6 @@ namespace MP.Data.Controllers
|
|||||||
return result != 0;
|
return result != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update record Registro Dichiarazioni
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="newRec"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<bool> RegDichiarUpdateAsync(RegistroDichiarazioniModel newRec)
|
|
||||||
{
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var Original_IdxDich = new SqlParameter("@Original_IdxDich", newRec.IdxDich);
|
|
||||||
var DtRec = new SqlParameter("@DtRec", newRec.DtRec);
|
|
||||||
var TagCode = new SqlParameter("@TagCode", newRec.TagCode);
|
|
||||||
var ValString = new SqlParameter("@ValString", newRec.ValString);
|
|
||||||
var MatrOpr = new SqlParameter("@MatrOpr", newRec.MatrOpr);
|
|
||||||
var result = await dbCtx
|
|
||||||
.Database
|
|
||||||
.ExecuteSqlRawAsync("exec dbo.stp_DD_updateQuery @Original_IdxDich, @DtRec, @TagCode, @ValString, @MatrOpr", Original_IdxDich, DtRec, TagCode, ValString, MatrOpr);
|
|
||||||
|
|
||||||
return result != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Aggiunta record RegistroScarti
|
/// Aggiunta record RegistroScarti
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1222,160 +854,6 @@ namespace MP.Data.Controllers
|
|||||||
return fatto;
|
return fatto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Aggiunta record RemoteRebootLog
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="newRec"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<bool> RemRebootLogAddAsync(RemoteRebootLogModel newRec)
|
|
||||||
{
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var dbResult = dbCtx
|
|
||||||
.DbSetRemRebLog
|
|
||||||
.Add(newRec);
|
|
||||||
|
|
||||||
return await dbCtx.SaveChangesAsync() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Recupera tutti i record di RemoteRebootLog
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<RemoteRebootLogModel>> RemRebootLogGetAllAsync()
|
|
||||||
{
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var dbResult = await dbCtx
|
|
||||||
.DbSetRemRebLog
|
|
||||||
.AsNoTracking()
|
|
||||||
.OrderByDescending(x => x.IdxReboot)
|
|
||||||
.ToListAsync();
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Recupera ultimo record x ogni IdxMacchina x avere ultimo attivo
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<RemoteRebootLogModel>> RemRebootLogGetLastAsync()
|
|
||||||
{
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
var dbResult = await dbCtx
|
|
||||||
.DbSetRemRebLog
|
|
||||||
.FromSqlRaw("EXEC stp_RRL_getLast")
|
|
||||||
.AsNoTracking()
|
|
||||||
.ToListAsync();
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Recupera ultimo record x ogni IdxMacchina x avere ultimo attivo
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<bool> RemRebootLogKeepLastAsync(int num2keep)
|
|
||||||
{
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var pNum2Keep = new SqlParameter("@num2keep", num2keep);
|
|
||||||
// La SP gestisce già la logica di soglia (1.5x), ma la specifico x sicurezza
|
|
||||||
var pThresh = new SqlParameter("@threshMult", 1.5);
|
|
||||||
var dbResult = await dbCtx.Database.ExecuteSqlRawAsync(
|
|
||||||
"EXEC dbo.stp_RRL_KeepLatest @num2keep, @threshMult", pNum2Keep, pThresh);
|
|
||||||
|
|
||||||
return dbResult != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Aggiunta record SignalLog Async
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="newRec"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<bool> SignalLogInsertAsync(SignalLogModel newRec)
|
|
||||||
{
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var currRec = dbCtx
|
|
||||||
.DbSetSignalLog
|
|
||||||
.Add(newRec);
|
|
||||||
|
|
||||||
return await dbCtx.SaveChangesAsync() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tabella state machine eventi 2 stati data macchina e tipo evento
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idxTipo"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<TransizioneStatiModel>> SMES_getHwTransitionsAsync(string idxMacchina, int idxTipo)
|
|
||||||
{
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacchina);
|
|
||||||
var IdxTipo = new SqlParameter("@IdxTipo", idxTipo);
|
|
||||||
var dbResult = await dbCtx
|
|
||||||
.DbSetSMES
|
|
||||||
.FromSqlRaw("exec dbo.stp_TS_getByIdxMacchIdxTipoEv @IdxMacchina, @IdxTipo", IdxMacchina, IdxTipo)
|
|
||||||
.AsNoTracking()
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tabella state machine eventi 2 stati data macchina e tipo evento
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idxTipo"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<TransizioneStatiModel>> SMES_getUserForcedAsync(string idxMacchina, int idxTipo)
|
|
||||||
{
|
|
||||||
await using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacchina);
|
|
||||||
var IdxTipo = new SqlParameter("@IdxTipo", idxTipo);
|
|
||||||
var dbResult = await dbCtx
|
|
||||||
.DbSetSMES
|
|
||||||
.FromSqlRaw("exec dbo.stp_TS_getUserForcedTrans @IdxMacchina, @IdxTipo", IdxMacchina, IdxTipo)
|
|
||||||
.AsNoTracking()
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Intera tabella state machine ingressi 2 eventi
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public List<TransizioneIngressiModel> StateMachineIngressi(int idxFam)
|
|
||||||
{
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
var IdxFamIn = new SqlParameter("@IdxFamigliaIngresso", idxFam);
|
|
||||||
return dbCtx
|
|
||||||
.DbSetSMI
|
|
||||||
.FromSqlRaw("exec dbo.stp_TRI_getByIdxFamIng @IdxFamigliaIngresso", IdxFamIn)
|
|
||||||
.AsNoTracking()
|
|
||||||
.AsEnumerable()
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Intera tabella state machine ingressi 2 eventi
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<TransizioneIngressiModel>> StateMachineIngressiAsync(int idxFam)
|
|
||||||
{
|
|
||||||
using var dbCtx = _ctxFactory.CreateDbContext();
|
|
||||||
|
|
||||||
var IdxFamIn = new SqlParameter("@IdxFamigliaIngresso", idxFam);
|
|
||||||
var dbResult = await dbCtx
|
|
||||||
.DbSetSMI
|
|
||||||
.FromSqlRaw("exec dbo.stp_TRI_getByIdxFamIng @IdxFamigliaIngresso", IdxFamIn)
|
|
||||||
.AsNoTracking()
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
return dbResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stato prod macchina (completo) Async
|
/// Stato prod macchina (completo) Async
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1457,24 +935,18 @@ namespace MP.Data.Controllers
|
|||||||
|
|
||||||
#endregion Public Methods
|
#endregion Public Methods
|
||||||
|
|
||||||
|
#region Protected Fields
|
||||||
|
|
||||||
|
protected readonly IDbContextFactory<MoonProContext> _ctxFactory;
|
||||||
|
protected readonly IDbContextFactory<MoonPro_FluxContext> _ctxFactoryFL;
|
||||||
|
|
||||||
|
#endregion Protected Fields
|
||||||
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
#if false
|
|
||||||
private static IConfiguration _configuration;
|
|
||||||
#endif
|
|
||||||
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
|
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
#if false
|
|
||||||
private DbContextOptions<MoonProContext> options;
|
|
||||||
#endif
|
|
||||||
private DbContextOptions<MoonPro_FluxContext> optionsFlux;
|
private DbContextOptions<MoonPro_FluxContext> optionsFlux;
|
||||||
|
|
||||||
#endregion Private Fields
|
#endregion Private Fields
|
||||||
|
|
||||||
#if false
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_configuration = null;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -35,9 +35,11 @@ namespace MP.Data
|
|||||||
// Repository Singleton
|
// Repository Singleton
|
||||||
services.TryAddSingleton<IMtcSetupRepository, MtcSetupRepository>();
|
services.TryAddSingleton<IMtcSetupRepository, MtcSetupRepository>();
|
||||||
services.TryAddSingleton<IProductionRepository, ProductionRepository>();
|
services.TryAddSingleton<IProductionRepository, ProductionRepository>();
|
||||||
|
services.TryAddSingleton<IIocRepository, IocRepository>();
|
||||||
|
services.TryAddSingleton<IAnagRepository, AnagRepository>();
|
||||||
|
services.TryAddSingleton<ISystemRepository, SystemRepository>();
|
||||||
|
|
||||||
// Repository Scoped
|
// Repository Scoped (non usate da MpDataService)
|
||||||
services.TryAddScoped<IIocRepository, IocRepository>();
|
|
||||||
services.TryAddScoped<IStatsAggrRepository, StatsAggrRepository>();
|
services.TryAddScoped<IStatsAggrRepository, StatsAggrRepository>();
|
||||||
services.TryAddScoped<IStatsDetailRepository, StatsDetailRepository>();
|
services.TryAddScoped<IStatsDetailRepository, StatsDetailRepository>();
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ namespace MP.Data.Repository.Anag
|
|||||||
{
|
{
|
||||||
AnagCountersModel answ = new AnagCountersModel();
|
AnagCountersModel answ = new AnagCountersModel();
|
||||||
await using var dbCtx = await CreateContextAsync();
|
await using var dbCtx = await CreateContextAsync();
|
||||||
bool outTable = true;
|
|
||||||
if (outTable)
|
|
||||||
{
|
|
||||||
var pCntType = new SqlParameter("@CntType", cntType);
|
var pCntType = new SqlParameter("@CntType", cntType);
|
||||||
var pLastNum = new SqlParameter
|
var pLastNum = new SqlParameter
|
||||||
{
|
{
|
||||||
@@ -38,44 +36,16 @@ namespace MP.Data.Repository.Anag
|
|||||||
Direction = ParameterDirection.Output
|
Direction = ParameterDirection.Output
|
||||||
};
|
};
|
||||||
|
|
||||||
var dbResult = await dbCtx
|
var dbResult = (await dbCtx
|
||||||
.DbSetAnagCount
|
.DbSetAnagCount
|
||||||
.FromSqlRaw("EXEC dbo.stp_getNextNumb @CntType, @LastNum OUTPUT", pCntType, pLastNum)
|
.FromSqlRaw("EXEC dbo.stp_getNextNumb @CntType, @LastNum OUTPUT", pCntType, pLastNum)
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.FirstOrDefaultAsync();
|
.ToListAsync()).FirstOrDefault();
|
||||||
if (dbResult != null)
|
if (dbResult != null)
|
||||||
{
|
{
|
||||||
answ = dbResult;
|
answ = dbResult;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// se si volessero impiegare parametri OUTPUT (qui ne mancherebbe 1 nella stored x CntCode...)
|
|
||||||
var pCntType = new SqlParameter("@CntType", cntType);
|
|
||||||
var pLastNum = new SqlParameter
|
|
||||||
{
|
|
||||||
ParameterName = "@LastNum",
|
|
||||||
SqlDbType = SqlDbType.Int,
|
|
||||||
Direction = ParameterDirection.Output
|
|
||||||
};
|
|
||||||
var pCntCode = new SqlParameter
|
|
||||||
{
|
|
||||||
ParameterName = "@CntCode",
|
|
||||||
SqlDbType = SqlDbType.NVarChar,
|
|
||||||
Direction = ParameterDirection.Output
|
|
||||||
};
|
|
||||||
var dbResult = await dbCtx
|
|
||||||
.Database
|
|
||||||
.ExecuteSqlRawAsync("EXEC dbo.stp_getNextNumb @CntType, @LastNum OUTPUT, @CntCode OUTPUT", pCntType, pLastNum, pCntCode);
|
|
||||||
if (dbResult != 0)
|
|
||||||
{
|
|
||||||
answ.CntType = cntType;
|
|
||||||
answ.CntCode = $"{pCntCode.Value}";
|
|
||||||
int lNum = 0;
|
|
||||||
int.TryParse($"{pLastNum.Value}", out lNum);
|
|
||||||
answ.LastNum = lNum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return answ;
|
return answ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,7 +322,7 @@ namespace MP.Data.Repository.Anag
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<bool> ArticoliUpdateRecord(AnagArticoliModel editRec)
|
public async Task<bool> ArticoliUpsertAsync(AnagArticoliModel editRec)
|
||||||
{
|
{
|
||||||
await using var dbCtx = await CreateContextAsync();
|
await using var dbCtx = await CreateContextAsync();
|
||||||
var currRec = await dbCtx.DbSetArticoli.FirstOrDefaultAsync(x => x.CodArticolo == editRec.CodArticolo);
|
var currRec = await dbCtx.DbSetArticoli.FirstOrDefaultAsync(x => x.CodArticolo == editRec.CodArticolo);
|
||||||
@@ -363,9 +333,12 @@ namespace MP.Data.Repository.Anag
|
|||||||
currRec.Tipo = editRec.Tipo;
|
currRec.Tipo = editRec.Tipo;
|
||||||
currRec.Azienda = editRec.Azienda;
|
currRec.Azienda = editRec.Azienda;
|
||||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||||
return await dbCtx.SaveChangesAsync() > 0;
|
|
||||||
}
|
}
|
||||||
return false;
|
else
|
||||||
|
{
|
||||||
|
dbCtx.DbSetArticoli.Add(editRec);
|
||||||
|
}
|
||||||
|
return await dbCtx.SaveChangesAsync() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -140,11 +140,11 @@ namespace MP.Data.Repository.Anag
|
|||||||
Task<List<AnagArticoliModel>> ArticoliInKitAsync();
|
Task<List<AnagArticoliModel>> ArticoliInKitAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update Record Articolo
|
/// Upsert (add/update) Record Articolo
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="editRec">Record da aggiornare</param>
|
/// <param name="editRec">Record da aggiornare</param>
|
||||||
/// <returns>True se aggiornato</returns>
|
/// <returns>True se aggiornato</returns>
|
||||||
Task<bool> ArticoliUpdateRecord(AnagArticoliModel editRec);
|
Task<bool> ArticoliUpsertAsync(AnagArticoliModel editRec);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Elenco Gruppi tipo REPARTOin formato DTO con conteggi del numero record trovati filtrati per operatore
|
/// Elenco Gruppi tipo REPARTOin formato DTO con conteggi del numero record trovati filtrati per operatore
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace MP.Data.Repository.Production
|
|||||||
|
|
||||||
Task<List<PODLExpModel>> ListPODL_ByKitParentAsync(int IdxPodlParent);
|
Task<List<PODLExpModel>> ListPODL_ByKitParentAsync(int IdxPodlParent);
|
||||||
|
|
||||||
Task<List<PODLExpModel>> ListPODL_KitFiltAsync(bool lanciato, string keyRichPart, string idxMacchina, string codGruppo, DateTime startDate, DateTime endDate);
|
Task<List<PODLExpModel>> ListPODL_KitFiltAsync(bool lanciato, string keyRichPart, string idxMacchina, string codGruppo, DateTime startDate, DateTime endDate, bool flagAttive, bool flagKitChild);
|
||||||
|
|
||||||
Task<PODLModel> PODL_getByKeyAsync(int idxPODL);
|
Task<PODLModel> PODL_getByKeyAsync(int idxPODL);
|
||||||
|
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ namespace MP.Data.Repository.Production
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<List<PODLExpModel>> ListPODL_KitFiltAsync(bool lanciato, string keyRichPart, string idxMacchina, string codGruppo, DateTime startDate, DateTime endDate)
|
public async Task<List<PODLExpModel>> ListPODL_KitFiltAsync(bool lanciato, string keyRichPart, string idxMacchina, string codGruppo, DateTime startDate, DateTime endDate, bool flagAttive, bool flagKitChild)
|
||||||
{
|
{
|
||||||
await using var dbCtx = await GetMoonProContextAsync();
|
await using var dbCtx = await GetMoonProContextAsync();
|
||||||
var Lanc = new SqlParameter("@Lanciato", lanciato);
|
var Lanc = new SqlParameter("@Lanciato", lanciato);
|
||||||
@@ -196,10 +196,13 @@ namespace MP.Data.Repository.Production
|
|||||||
var IdxMacc = new SqlParameter("@IdxMacchina", idxMacchina);
|
var IdxMacc = new SqlParameter("@IdxMacchina", idxMacchina);
|
||||||
var DateFrom = new SqlParameter("@DtInizio", startDate);
|
var DateFrom = new SqlParameter("@DtInizio", startDate);
|
||||||
var DateTo = new SqlParameter("@DtFine", endDate);
|
var DateTo = new SqlParameter("@DtFine", endDate);
|
||||||
|
var pFlagAtt = new SqlParameter("@flgAttive", flagAttive);
|
||||||
|
var pFlagKit = new SqlParameter("@flgPodlKit", true);
|
||||||
|
var pFlagKChild = new SqlParameter("@flgPodChild", flagKitChild);
|
||||||
|
|
||||||
return await dbCtx
|
return await dbCtx
|
||||||
.DbSetPODLExp
|
.DbSetPODLExp
|
||||||
.FromSqlRaw("EXEC stp_PODL_getByFiltSpecKit @Lanciato, @KeyRich, @CodGruppo, @IdxMacchina, @DtInizio, @DtFine", Lanc, KeyRich, CodGrp, IdxMacc, DateFrom, DateTo)
|
.FromSqlRaw("EXEC stp_PODL_getByFiltSpecKit @Lanciato, @KeyRich, @CodGruppo, @IdxMacchina, @DtInizio, @DtFine, @flgAttive, @flgPodlKit, @flgPodChild", Lanc, KeyRich, CodGrp, IdxMacc, DateFrom, DateTo, pFlagAtt, pFlagKit, pFlagKChild)
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using System.Linq;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
using ZiggyCreatures.Caching.Fusion;
|
||||||
using static Org.BouncyCastle.Asn1.Cmp.Challenge;
|
|
||||||
|
|
||||||
namespace MP.Data.Services
|
namespace MP.Data.Services
|
||||||
{
|
{
|
||||||
@@ -54,6 +53,35 @@ namespace MP.Data.Services
|
|||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancellazione FusionCache (totale) - wrapper public
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task<bool> ForceFlushFusionCacheAsync()
|
||||||
|
{
|
||||||
|
return FlushFusionCacheAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancellazione Fusion Cache x tag (wrapper)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task<bool> ForceFlushFusionCacheAsync(string tag)
|
||||||
|
{
|
||||||
|
return FlushFusionCacheAsync(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancellazione Fusion Cache x list tags (wrapper)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="listTags"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task<bool> ForceFlushFusionCacheAsync(List<string> listTags)
|
||||||
|
{
|
||||||
|
return FlushFusionCacheAsync(listTags);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Recupero info IOB x TAB (da info registrate IOB-WIN--> MP-IO)
|
/// Recupero info IOB x TAB (da info registrate IOB-WIN--> MP-IO)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -340,8 +368,8 @@ namespace MP.Data.Services
|
|||||||
var cacheOptions = new FusionCacheEntryOptions()
|
var cacheOptions = new FusionCacheEntryOptions()
|
||||||
.SetDuration(expiration)
|
.SetDuration(expiration)
|
||||||
.SetFailSafe(true);
|
.SetFailSafe(true);
|
||||||
// cache in RAM per 1/3 del tempo x risparmiare risorse
|
// cache in RAM per 1/2 del tempo x risparmiare risorse
|
||||||
cacheOptions.MemoryCacheDuration = expiration / 3;
|
cacheOptions.MemoryCacheDuration = expiration / 2;
|
||||||
|
|
||||||
var final = await _cache.GetOrSetAsync<T>(
|
var final = await _cache.GetOrSetAsync<T>(
|
||||||
cacheKey,
|
cacheKey,
|
||||||
@@ -525,5 +553,50 @@ namespace MP.Data.Services
|
|||||||
private double slowLogThresh = 0;
|
private double slowLogThresh = 0;
|
||||||
|
|
||||||
#endregion Private Fields
|
#endregion Private Fields
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancellazione FusionCache (totale)
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task<bool> FlushFusionCacheAsync()
|
||||||
|
{
|
||||||
|
await _cache.ClearAsync(allowFailSafe: false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancellazione FusionCache dato singolo tag
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task<bool> FlushFusionCacheAsync(string tag)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(tag)) return false;
|
||||||
|
|
||||||
|
await _cache.RemoveByTagAsync(tag);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancellazione FusionCache dato elenco tags
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="listTags"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task<bool> FlushFusionCacheAsync(List<string> listTags)
|
||||||
|
{
|
||||||
|
if (listTags == null || listTags.Count == 0) return false;
|
||||||
|
|
||||||
|
// Generiamo i Task di rimozione ed eseguiamoli in parallelo su Redis/L1
|
||||||
|
var tasks = listTags
|
||||||
|
.Where(tag => !string.IsNullOrWhiteSpace(tag))
|
||||||
|
.Select(tag => _cache.RemoveByTagAsync(tag).AsTask());
|
||||||
|
|
||||||
|
await Task.WhenAll(tasks);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Private Methods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,20 @@ namespace MP.Data.Services.IOC
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> ClearFusionCache();
|
Task<bool> ClearFusionCache();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Esegue flush della cache fusion dato tag
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<bool> ClearFusionCache(string tag);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Esegue flush della cache fusion data list tags
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="listTags"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<bool> ClearFusionCache(List<string> listTags);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Aggiunta record MicroStato + EventList
|
/// Aggiunta record MicroStato + EventList
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -58,6 +58,29 @@ namespace MP.Data.Services.IOC
|
|||||||
return fatto;
|
return fatto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<bool> ClearFusionCache(string tag)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(tag)) return false;
|
||||||
|
|
||||||
|
await _cache.RemoveByTagAsync(tag);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<bool> ClearFusionCache(List<string> listTags)
|
||||||
|
{
|
||||||
|
if (listTags == null || listTags.Count == 0) return false;
|
||||||
|
|
||||||
|
// Generiamo i Task di rimozione ed eseguiamoli in parallelo su Redis/L1
|
||||||
|
var tasks = listTags
|
||||||
|
.Where(tag => !string.IsNullOrWhiteSpace(tag))
|
||||||
|
.Select(tag => _cache.RemoveByTagAsync(tag).AsTask());
|
||||||
|
|
||||||
|
await Task.WhenAll(tasks);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<bool> EvListMicroStatoInsertAsync(MicroStatoMacchinaModel newRecMsm, EventListModel newRecEv)
|
public async Task<bool> EvListMicroStatoInsertAsync(MicroStatoMacchinaModel newRecMsm, EventListModel newRecEv)
|
||||||
{
|
{
|
||||||
@@ -68,6 +91,19 @@ namespace MP.Data.Services.IOC
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<string> GetCurrOdlAsync(string idxMacchina)
|
public async Task<string> GetCurrOdlAsync(string idxMacchina)
|
||||||
{
|
{
|
||||||
|
string cKey = $"{MP.Data.Utils.redisOdlCurrByMac}:{idxMacchina}";
|
||||||
|
return await GetOrFetchAsync(
|
||||||
|
operationName: "GetCurrOdlAsync",
|
||||||
|
cacheKey: cKey,
|
||||||
|
fetchFunc: async () =>
|
||||||
|
{
|
||||||
|
return await GetCurrOdlByProdAsync(idxMacchina);
|
||||||
|
},
|
||||||
|
expiration: GetRandTOut(redisLongTimeCache),
|
||||||
|
tagList: [idxMacchina]
|
||||||
|
);
|
||||||
|
|
||||||
|
#if false
|
||||||
string result = "";
|
string result = "";
|
||||||
string currKey = $"{MP.Data.Utils.redisOdlCurrByMac}:{idxMacchina}";
|
string currKey = $"{MP.Data.Utils.redisOdlCurrByMac}:{idxMacchina}";
|
||||||
// cerco in redis dato valOut sel macchina...
|
// cerco in redis dato valOut sel macchina...
|
||||||
@@ -79,11 +115,10 @@ namespace MP.Data.Services.IOC
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = await GetCurrOdlByProdAsync(idxMacchina);
|
result = await GetCurrOdlByProdAsync(idxMacchina);
|
||||||
// serializzo e salvo...
|
_redisDb.StringSet(currKey, result, GetRandTOut(redisShortTimeCache));
|
||||||
rawData = JsonConvert.SerializeObject(result);
|
|
||||||
_redisDb.StringSet(currKey, rawData, GetRandTOut(redisLongTimeCache));
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -96,21 +131,48 @@ namespace MP.Data.Services.IOC
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<bool> IobInsEnabAsync(string idxMacchina)
|
public async Task<bool> IobInsEnabAsync(string idxMacchina)
|
||||||
{
|
{
|
||||||
string cacheKey = $"IOC_IobInsEnab_{idxMacchina}";
|
string cKey = $"IOC_IobInsEnab_{idxMacchina}";
|
||||||
return await GetOrFetchAsync(cacheKey, async () =>
|
return await GetOrFetchAsync(
|
||||||
|
operationName: "StatoProdMacchinaAsync",
|
||||||
|
cacheKey: cKey,
|
||||||
|
fetchFunc: async () =>
|
||||||
{
|
{
|
||||||
var key = MP.Data.Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
var rKey = MP.Data.Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
||||||
|
var val = await _redisDb.HashGetAsync(rKey, "insEnabled");
|
||||||
|
|
||||||
string? val = await _redisDb.HashGetAsync(key, "insEnabled");
|
if (!val.HasValue)
|
||||||
|
|
||||||
if (val == null)
|
|
||||||
{
|
{
|
||||||
var data = await ResetDatiMacchinaAsync(idxMacchina);
|
var data = await ResetDatiMacchinaAsync(idxMacchina);
|
||||||
data.TryGetValue("insEnabled", out val);
|
// 2. Uso del pattern matching per evitare allocazioni e passaggi intermedi
|
||||||
|
return data != null
|
||||||
|
&& data.TryGetValue("insEnabled", out string? sVal)
|
||||||
|
&& IsStringTrue(sVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
return val != null && (val == "1" || val.ToLower() == "true");
|
// 3. Conversione efficiente da RedisValue a string (evita l'interpolazione $"{val}")
|
||||||
}, TimeSpan.FromSeconds(5));
|
string? sRedisVal = val;
|
||||||
|
return IsStringTrue(sRedisVal);
|
||||||
|
|
||||||
|
#if false
|
||||||
|
var rKey = MP.Data.Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
||||||
|
var val = await _redisDb.HashGetAsync(rKey, "insEnabled");
|
||||||
|
string sVal = "";
|
||||||
|
if (!val.HasValue)
|
||||||
|
{
|
||||||
|
var data = await ResetDatiMacchinaAsync(idxMacchina);
|
||||||
|
data.TryGetValue("insEnabled", out sVal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sVal = $"{val}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return !string.IsNullOrEmpty(sVal) && (sVal == "1" || sVal.ToLower() == "true");
|
||||||
|
#endif
|
||||||
|
},
|
||||||
|
expiration: GetRandTOut(30),
|
||||||
|
tagList: ["IOC_IobInsEnab", cKey, idxMacchina]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -181,8 +243,7 @@ namespace MP.Data.Services.IOC
|
|||||||
public async Task<int> PzCounterTcAsync(string idxMacchina)
|
public async Task<int> PzCounterTcAsync(string idxMacchina)
|
||||||
{
|
{
|
||||||
int answ = -1;
|
int answ = -1;
|
||||||
DateTime dataRif = DateTime.Now;
|
var datiProd = await StatoProdMacchinaAsync(idxMacchina, DateTime.Now);
|
||||||
var datiProd = await StatoProdMacchinaAsync(idxMacchina, dataRif);
|
|
||||||
if (datiProd != null)
|
if (datiProd != null)
|
||||||
{
|
{
|
||||||
answ = datiProd.PzTotODL;
|
answ = datiProd.PzTotODL;
|
||||||
@@ -230,6 +291,7 @@ namespace MP.Data.Services.IOC
|
|||||||
answ = currCount.ToString();
|
answ = currCount.ToString();
|
||||||
// salvo per meno tempo...
|
// salvo per meno tempo...
|
||||||
await _redisDb.StringSetAsync(currKey, answ);
|
await _redisDb.StringSetAsync(currKey, answ);
|
||||||
|
await ClearFusionCache(idxMacchina);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,7 +323,38 @@ namespace MP.Data.Services.IOC
|
|||||||
|
|
||||||
#endregion Protected Fields
|
#endregion Protected Fields
|
||||||
|
|
||||||
#region Protected Methods
|
#region Private Fields
|
||||||
|
|
||||||
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
private readonly string _className;
|
||||||
|
|
||||||
|
private readonly IIocRepository _repo;
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
||||||
|
#endregion Private Fields
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
|
||||||
|
private static bool IsStringTrue(string? value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value)) return false;
|
||||||
|
|
||||||
|
// Evita ToLower() che alloca una nuova stringa in memoria ad ogni chiamata
|
||||||
|
return value == "1"
|
||||||
|
|| value.Equals("true", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
#if false
|
#if false
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -275,42 +368,15 @@ namespace MP.Data.Services.IOC
|
|||||||
return TimeSpan.FromMinutes(rndValue);
|
return TimeSpan.FromMinutes(rndValue);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endregion Protected Methods
|
|
||||||
|
|
||||||
#region Private Fields
|
|
||||||
|
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
|
||||||
|
|
||||||
#if false
|
#if false
|
||||||
private readonly IFusionCache _cache;
|
private readonly IFusionCache _cache;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private readonly string _className;
|
|
||||||
|
|
||||||
private readonly IIocRepository _repo;
|
|
||||||
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";
|
|
||||||
|
|
||||||
#if false
|
#if false
|
||||||
private int redisLongTimeCache = 5;
|
private int redisLongTimeCache = 5;
|
||||||
|
|
||||||
private int redisShortTimeCache = 2;
|
private int redisShortTimeCache = 2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endregion Private Fields
|
|
||||||
|
|
||||||
#region Private Methods
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// controlla se da il segnale di "microstato" deriva un evento da generare - modalità OFFLINE
|
/// controlla se da il segnale di "microstato" deriva un evento da generare - modalità OFFLINE
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -467,7 +533,7 @@ namespace MP.Data.Services.IOC
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implementa gestione recupero cache da memoria o da obj esterno + cache memoria
|
/// Implementa gestione recupero cache da memoria o da obj esterno + cache memoria (versione semplificata)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <param name="cacheKey"></param>
|
/// <param name="cacheKey"></param>
|
||||||
@@ -493,26 +559,20 @@ namespace MP.Data.Services.IOC
|
|||||||
{
|
{
|
||||||
bool answ = false;
|
bool answ = false;
|
||||||
// ORA recupero da memoria redis...
|
// ORA recupero da memoria redis...
|
||||||
try
|
var rKey = MP.Data.Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
||||||
{
|
RedisValue rawData = await _redisDb.HashGetAsync(rKey, (RedisValue)"sLogEnabled");
|
||||||
var currHash = MP.Data.Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
|
|
||||||
RedisValue rawData = await _redisDb.HashGetAsync(currHash, (RedisValue)"sLogEnabled");
|
|
||||||
// se è vuoto... leggo da DB e popolo!
|
// se è vuoto... leggo da DB e popolo!
|
||||||
if (!rawData.HasValue)
|
if (!rawData.HasValue)
|
||||||
{
|
{
|
||||||
await ResetDatiMacchinaAsync(idxMacchina);
|
var data = await ResetDatiMacchinaAsync(idxMacchina);
|
||||||
// riprovo
|
|
||||||
rawData = await _redisDb.HashGetAsync(currHash, (RedisValue)"sLogEnabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
// provo conversione
|
// 2. Uso del pattern matching per evitare allocazioni e passaggi intermedi
|
||||||
bool.TryParse($"{rawData}", out answ);
|
return data != null
|
||||||
|
&& data.TryGetValue("sLogEnabled", out string? sVal)
|
||||||
|
&& IsStringTrue(sVal);
|
||||||
}
|
}
|
||||||
catch (Exception exc)
|
string? sRedisVal = rawData;
|
||||||
{
|
return IsStringTrue(sRedisVal);
|
||||||
Log.Error($"Errore IobSLogEnabAsync | idxMacchina {idxMacchina}:{Environment.NewLine}{exc}");
|
|
||||||
}
|
|
||||||
return answ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -832,7 +892,7 @@ namespace MP.Data.Services.IOC
|
|||||||
result.Add("palletChange", $"{dbResult.PalletChange}");
|
result.Add("palletChange", $"{dbResult.PalletChange}");
|
||||||
// durata cache in secondi dal valOut insEnabled...
|
// durata cache in secondi dal valOut insEnabled...
|
||||||
//double numSecCache = ((result["insEnabled"].ToLower() == "true") ? redisShortTimeCache : redisLongTimeCache);
|
//double numSecCache = ((result["insEnabled"].ToLower() == "true") ? redisShortTimeCache : redisLongTimeCache);
|
||||||
numSecCache = dbResult.InsEnabled ? redisShortTimeCache : redisLongTimeCache;
|
numSecCache = dbResult.InsEnabled ? redisShortTimeCache * 2 : redisLongTimeCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dati master/slave
|
// dati master/slave
|
||||||
@@ -853,10 +913,12 @@ namespace MP.Data.Services.IOC
|
|||||||
// 3. Inseriamo i nuovi valori
|
// 3. Inseriamo i nuovi valori
|
||||||
_ = transaction.HashSetAsync(redKey, entries);
|
_ = transaction.HashSetAsync(redKey, entries);
|
||||||
// 4. Impostiamo l'expiration in un unico colpo
|
// 4. Impostiamo l'expiration in un unico colpo
|
||||||
_ = transaction.KeyExpireAsync(redKey, TimeSpan.FromSeconds(numSecCache));
|
_ = transaction.KeyExpireAsync(redKey, GetRandTOut(numSecCache));
|
||||||
// Eseguiamo tutto in un unico viaggio verso Redis
|
// Eseguiamo tutto in un unico viaggio verso Redis
|
||||||
bool success = await transaction.ExecuteAsync();
|
bool success = await transaction.ExecuteAsync();
|
||||||
|
|
||||||
|
await ForceFlushFusionCacheAsync(idxMacc);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1011,9 +1073,13 @@ namespace MP.Data.Services.IOC
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task<StatoProdModel> StatoProdMacchinaAsync(string idxMacchina, DateTime dtReq, bool forceDb = false)
|
private async Task<StatoProdModel> StatoProdMacchinaAsync(string idxMacchina, DateTime dtReq, bool forceDb = false)
|
||||||
{
|
{
|
||||||
string cacheKey = $"IOC_StatoProd_{idxMacchina}";
|
string cKey = $"{MP.Data.Utils.redisStatoProd}:{idxMacchina}";
|
||||||
return await GetOrFetchAsync(cacheKey, async () =>
|
return await GetOrFetchAsync(
|
||||||
|
operationName: "StatoProdMacchinaAsync",
|
||||||
|
cacheKey: cKey,
|
||||||
|
fetchFunc: async () =>
|
||||||
{
|
{
|
||||||
|
#if false
|
||||||
StatoProdModel? result = new StatoProdModel();
|
StatoProdModel? result = new StatoProdModel();
|
||||||
// cerco in _redisConn...
|
// cerco in _redisConn...
|
||||||
string currKey = $"{MP.Data.Utils.redisStatoProd}:{idxMacchina}:{dtReq:HHmm}";
|
string currKey = $"{MP.Data.Utils.redisStatoProd}:{idxMacchina}:{dtReq:HHmm}";
|
||||||
@@ -1027,14 +1093,19 @@ namespace MP.Data.Services.IOC
|
|||||||
result = await _repo.StatoProdMacchinaAsync(idxMacchina, dtReq);
|
result = await _repo.StatoProdMacchinaAsync(idxMacchina, dtReq);
|
||||||
// serializzo e salvo...
|
// serializzo e salvo...
|
||||||
rawData = JsonConvert.SerializeObject(result);
|
rawData = JsonConvert.SerializeObject(result);
|
||||||
await _redisDb.StringSetAsync(currKey, rawData, TimeSpan.FromSeconds(30));
|
await _redisDb.StringSetAsync(currKey, rawData, stdTTL);
|
||||||
}
|
}
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
result = new StatoProdModel();
|
result = new StatoProdModel();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}, TimeSpan.FromSeconds(3));
|
#endif
|
||||||
|
return await _repo.StatoProdMacchinaAsync(idxMacchina, dtReq);
|
||||||
|
},
|
||||||
|
expiration: GetRandTOut(redisLongTimeCache),
|
||||||
|
tagList: ["IOC_StatoProd", cKey, idxMacchina]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<RootNamespace>MP.INVE</RootNamespace>
|
<RootNamespace>MP.INVE</RootNamespace>
|
||||||
<Version>8.16.2606.408</Version>
|
<Version>8.16.2606.1117</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<i>Modulo MAPOINVE </i>
|
<i>Modulo MAPOINVE </i>
|
||||||
<h4>Versione: 8.16.2606.408</h4>
|
<h4>Versione: 8.16.2606.1117</h4>
|
||||||
<br /> Note di rilascio:
|
<br /> Note di rilascio:
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
8.16.2606.408
|
8.16.2606.1117
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<item>
|
<item>
|
||||||
<version>8.16.2606.408</version>
|
<version>8.16.2606.1117</version>
|
||||||
<url>https://nexus.steamware.net/repository/SWS/MP-INVE/stable/LAST/MP.INVE.zip</url>
|
<url>https://nexus.steamware.net/repository/SWS/MP-INVE/stable/LAST/MP.INVE.zip</url>
|
||||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-INVE/stable/LAST/ChangeLog.html</changelog>
|
<changelog>https://nexus.steamware.net/repository/SWS/MP-INVE/stable/LAST/ChangeLog.html</changelog>
|
||||||
<mandatory>false</mandatory>
|
<mandatory>false</mandatory>
|
||||||
|
|||||||
@@ -13,10 +13,9 @@ namespace MP.IOC.Controllers
|
|||||||
{
|
{
|
||||||
#region Public Constructors
|
#region Public Constructors
|
||||||
|
|
||||||
public BenchController(IConfiguration configuration, MpDataService DataService)
|
public BenchController(MpDataService DataService)
|
||||||
{
|
{
|
||||||
Log.Info("Starting BenchController");
|
Log.Info("Starting BenchController");
|
||||||
_configuration = configuration;
|
|
||||||
DService = DataService;
|
DService = DataService;
|
||||||
Log.Info("Avviata BenchController");
|
Log.Info("Avviata BenchController");
|
||||||
}
|
}
|
||||||
@@ -378,8 +377,6 @@ namespace MP.IOC.Controllers
|
|||||||
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private static IConfiguration _configuration = null!;
|
|
||||||
|
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
#endregion Private Fields
|
#endregion Private Fields
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ namespace MP.IOC.Controllers
|
|||||||
|
|
||||||
public IOBController(IConfiguration configuration, MpDataService DataService, IIocService IService)
|
public IOBController(IConfiguration configuration, MpDataService DataService, IIocService IService)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
|
||||||
DService = DataService;
|
DService = DataService;
|
||||||
IOCService = IService;
|
IOCService = IService;
|
||||||
}
|
}
|
||||||
@@ -76,41 +75,61 @@ namespace MP.IOC.Controllers
|
|||||||
return Ok(answ);
|
return Ok(answ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
#if false
|
||||||
/// GET: IOB/
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpGet]
|
|
||||||
public IActionResult Alive()
|
|
||||||
{
|
|
||||||
return Ok("OK"); // Restituisce Status 200
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GET: IOB/enabled/SIMUL_03
|
/// GET: IOB/enabled/SIMUL_03
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id"></param>
|
/// <param name="id"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpGet("enabled/{id}")]
|
[HttpGet("enabled/{id}")]
|
||||||
public async Task<IActionResult> Enabled(string id)
|
public async Task<string> Enabled(string id)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID");
|
if (string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||||
|
return "Missing ID";
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Il metodo ora restituisce direttamente il booleano logico
|
// Il metodo ora restituisce direttamente il booleano logico
|
||||||
bool isEnabled = await IOCService.IobInsEnabAsync(id);
|
bool isEnabled = await IOCService.IobInsEnabAsync(id);
|
||||||
|
|
||||||
return isEnabled
|
// Eliminazione delle allocazioni di stringhe e oggetti inutili
|
||||||
? Ok("OK")
|
if (!isEnabled)
|
||||||
: UnprocessableEntity("NO");
|
{
|
||||||
|
Response.StatusCode = StatusCodes.Status422UnprocessableEntity;
|
||||||
|
return "NO";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status 200 di default, scrive direttamente sul body della response
|
||||||
|
return "OK";
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error(ex, "Errore durante la verifica abilitazione per {Id}", id);
|
Log.Error(ex, "Errore durante la verifica abilitazione per {Id}", id);
|
||||||
return StatusCode(500, "Errore interno del server");
|
Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
return "Errore interno del server";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if (string.IsNullOrEmpty(id)) return BadRequest("Missing ID");
|
||||||
|
|
||||||
|
//try
|
||||||
|
//{
|
||||||
|
// // Il metodo ora restituisce direttamente il booleano logico
|
||||||
|
// bool isEnabled = await IOCService.IobInsEnabAsync(id);
|
||||||
|
|
||||||
|
// return isEnabled
|
||||||
|
// ? Ok("OK")
|
||||||
|
// : UnprocessableEntity("NO");
|
||||||
|
//}
|
||||||
|
//catch (Exception ex)
|
||||||
|
//{
|
||||||
|
// Log.Error(ex, "Errore durante la verifica abilitazione per {Id}", id);
|
||||||
|
// return StatusCode(500, "Errore interno del server");
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processa una chiamata POST per l'invio di un array Json di oggetti input (EVENTI)
|
/// Processa una chiamata POST per l'invio di un array Json di oggetti input (EVENTI)
|
||||||
@@ -464,6 +483,7 @@ namespace MP.IOC.Controllers
|
|||||||
return Ok(actValues);
|
return Ok(actValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if false
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Recupera ODL corrente x macchina:
|
/// Recupera ODL corrente x macchina:
|
||||||
/// GET: IOB/getCurrODL/SIMUL_03
|
/// GET: IOB/getCurrODL/SIMUL_03
|
||||||
@@ -480,16 +500,15 @@ namespace MP.IOC.Controllers
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var odl = await IOCService.GetCurrOdlAsync(id);
|
var odl = await IOCService.GetCurrOdlAsync(id);
|
||||||
//var odl = await DService.GetCurrOdlAsync(id);
|
|
||||||
return Ok($"{odl}");
|
return Ok($"{odl}");
|
||||||
}
|
}
|
||||||
catch (Exception exc)
|
catch (Exception exc)
|
||||||
{
|
{
|
||||||
Log.Error(exc, "Errore GetCurrODL | macchina {MachineId}", id);
|
Log.Error(exc, "Errore GetCurrODL | macchina {MachineId}", id);
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError, "NO");
|
return StatusCode(StatusCodes.Status500InternalServerError, "NO");
|
||||||
//return StatusCode(StatusCodes.Status500InternalServerError, "Errore interno | GetCurrODL");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Restituisce la quantità pezzi dell'odl correntemente in lavorazione sulla macchina...
|
/// Restituisce la quantità pezzi dell'odl correntemente in lavorazione sulla macchina...
|
||||||
@@ -1089,6 +1108,7 @@ namespace MP.IOC.Controllers
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
answ = await DService.saveCaricoPezzi(id, qty);
|
answ = await DService.saveCaricoPezzi(id, qty);
|
||||||
|
await IOCService.ClearFusionCache(id);
|
||||||
return Ok(answ);
|
return Ok(answ);
|
||||||
}
|
}
|
||||||
catch (Exception exc)
|
catch (Exception exc)
|
||||||
@@ -1207,6 +1227,7 @@ namespace MP.IOC.Controllers
|
|||||||
return Ok(answ);
|
return Ok(answ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if false
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SALVA Counter x macchina restituendo il valore appena inviato o, se mancasse chiave
|
/// SALVA Counter x macchina restituendo il valore appena inviato o, se mancasse chiave
|
||||||
/// redis, valore da DB ///
|
/// redis, valore da DB ///
|
||||||
@@ -1238,6 +1259,7 @@ namespace MP.IOC.Controllers
|
|||||||
}
|
}
|
||||||
return Ok(answ);
|
return Ok(answ);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Salva associazione tra macchina, device IOB chiamante e sue info
|
/// Salva associazione tra macchina, device IOB chiamante e sue info
|
||||||
@@ -1451,8 +1473,6 @@ namespace MP.IOC.Controllers
|
|||||||
#endregion Public Methods
|
#endregion Public Methods
|
||||||
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private static IConfiguration _configuration = null!;
|
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
private IIocService IOCService;
|
private IIocService IOCService;
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,9 @@ namespace MP.IOC.Controllers
|
|||||||
{
|
{
|
||||||
#region Public Constructors
|
#region Public Constructors
|
||||||
|
|
||||||
public RecipeArchiveController(IConfiguration configuration, MpDataService DataService)
|
public RecipeArchiveController(MpDataService DataService)
|
||||||
{
|
{
|
||||||
Log.Info("Starting RecipeArchiveController");
|
Log.Info("Starting RecipeArchiveController");
|
||||||
_configuration = configuration;
|
|
||||||
DService = DataService;
|
DService = DataService;
|
||||||
Log.Info("Avviata classe RecipeArchiveController");
|
Log.Info("Avviata classe RecipeArchiveController");
|
||||||
}
|
}
|
||||||
@@ -121,8 +120,6 @@ namespace MP.IOC.Controllers
|
|||||||
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private static IConfiguration _configuration = null!;
|
|
||||||
|
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
#endregion Private Fields
|
#endregion Private Fields
|
||||||
|
|||||||
@@ -12,10 +12,9 @@ namespace MP.IOC.Controllers
|
|||||||
{
|
{
|
||||||
#region Public Constructors
|
#region Public Constructors
|
||||||
|
|
||||||
public RecipeController(IConfiguration configuration, MpDataService DataService)
|
public RecipeController(MpDataService DataService)
|
||||||
{
|
{
|
||||||
Log.Info("Starting RecipeController");
|
Log.Info("Starting RecipeController");
|
||||||
_configuration = configuration;
|
|
||||||
DService = DataService;
|
DService = DataService;
|
||||||
Log.Info("Avviata RecipeController");
|
Log.Info("Avviata RecipeController");
|
||||||
}
|
}
|
||||||
@@ -64,8 +63,6 @@ namespace MP.IOC.Controllers
|
|||||||
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private static IConfiguration _configuration = null!;
|
|
||||||
|
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
#endregion Private Fields
|
#endregion Private Fields
|
||||||
|
|||||||
@@ -0,0 +1,620 @@
|
|||||||
|
using MP.Core.DTO;
|
||||||
|
using MP.Core.Objects;
|
||||||
|
using MP.Data.DbModels;
|
||||||
|
using MP.Data.DbModels.Anag;
|
||||||
|
using MP.Data.MgModels;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
using static MP.Core.Objects.Enums;
|
||||||
|
|
||||||
|
namespace MP.IOC.Data
|
||||||
|
{
|
||||||
|
public interface IMpDataService
|
||||||
|
{
|
||||||
|
#region Public Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifica se sia da reinviare un taskName alla macchina dall'elenco di quelli salvati (in
|
||||||
|
/// modalit\u00e0 upsert) se non scaduti
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="taskKey">tipo task</param>
|
||||||
|
/// <param name="taskVal">valore task</param>
|
||||||
|
/// <returns>true se il task \u00e8 stato reinviato</returns>
|
||||||
|
bool AddCheckTask4Machine(string idxMacchina, taskType taskKey, string taskVal);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aggiunge un parametro opzionale all'elenco dei saved task (in modalit\u00e0 upsert)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="taskKey">chiave del parametro</param>
|
||||||
|
/// <param name="taskVal">valore del parametro</param>
|
||||||
|
/// <returns>true se inserito</returns>
|
||||||
|
bool AddOptPar4Machine(string idxMacchina, string taskKey, string taskVal);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aggiunge un task all'elenco di quelli salvati (in modalit\u00e0 upsert)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="taskKey">tipo task</param>
|
||||||
|
/// <param name="taskVal">valore task</param>
|
||||||
|
/// <returns>true se inserito</returns>
|
||||||
|
bool AddTask4Machine(string idxMacchina, taskType taskKey, string taskVal);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aggiunge un set di task per macchina all'elenco di quelli salvati (in modalit\u00e0 upsert)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="taskDict"> Dizionario di task tipo-valore da salvare</param>
|
||||||
|
/// <returns>true se completato</returns>
|
||||||
|
Task<bool> AddTask4MacListAsync(string idxMacchina, Dictionary<taskType, string> taskDict);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserimento record allarme su DB
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dtRif">Data evento</param>
|
||||||
|
/// <param name="idxMacchina">Nome macchina</param>
|
||||||
|
/// <param name="memAddress">Indirizzo memoria PLC</param>
|
||||||
|
/// <param name="memIndex">Indice memoria</param>
|
||||||
|
/// <param name="statusVal">Stato valOut</param>
|
||||||
|
/// <param name="valDecoded">Valore decodificato</param>
|
||||||
|
/// <returns>true se inserito</returns>
|
||||||
|
Task<bool> AlarmInsertAsync(DateTime dtRif, string idxMacchina, string memAddress, int memIndex, int statusVal, string valDecoded);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce l'anagrafica STATI per intero con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Lista di modelli AnagStatiModel</returns>
|
||||||
|
Task<List<AnagStatiModel>> AnagStatiGetAllAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce i modelli di ultimo articolo per data macchina, con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacc">idx macchina</param>
|
||||||
|
/// <returns>Lista di modelli AnagArticoliModel</returns>
|
||||||
|
Task<List<AnagArticoliModel>> ArticoliGetLastByMaccAsync(string idxMacc);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Effettua lo split dell'ODL corrente per la macchina, con eventuale conferma produzione e
|
||||||
|
/// gestione slave
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="doConfirm">effettuare la conferma quantitativa</param>
|
||||||
|
/// <param name="qtyFromLast">imposta la qty del prossimo ODL da quello che si chiude</param>
|
||||||
|
/// <param name="matrOpr">matricola operatore</param>
|
||||||
|
/// <param name="roundStep">Step di arrotondamento quantit\u00e0</param>
|
||||||
|
/// <param name="keyRichiesta">Chiave esterna da associare all'ODL</param>
|
||||||
|
/// <returns>"OK" se successo, "KO" altrimenti</returns>
|
||||||
|
Task<string> AutoStartOdlAsync(string idxMacchina, bool doConfirm, bool qtyFromLast, int matrOpr, int roundStep = 100, string keyRichiesta = "");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calcola la ricetta su MongoDB dato modello ricetta corrente
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="currRecipe">Modello ricetta da calcolare</param>
|
||||||
|
/// <returns>Risultato del calcolo ricetta</returns>
|
||||||
|
string CalcRecipe(RecipeModel currRecipe);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controlla se dal segnale di "microstato" deriva un evento da generare - modalit\u00e0 OFFLINE
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="valore">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>Risultato del processing</returns>
|
||||||
|
Task<inputComandoMapo> CheckMicroStatoAsync(string idxMacchina, string valore, DateTime dtEve, string contatore, Dictionary<string, string>? datiMaccCache = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce l'elenco completo delle configurazioni da DB, con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Lista di modelli ConfigModel</returns>
|
||||||
|
Task<List<ConfigModel>> ConfigGetAllAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce l'elenco delle decodifiche articoli filtrata per codice, con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="codArt">codice articolo (opzionale, se vuoto restituisce tutto)</param>
|
||||||
|
/// <returns>Lista di modelli DecNumArticoliModel</returns>
|
||||||
|
Task<List<DecNumArticoliModel>> DecNumArtGetFiltAsync(string codArt = "");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce le date dei dossier per una macchina, con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Lista di modelli DossierModel</returns>
|
||||||
|
Task<List<DossierModel>> DossierLastByMachAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Task completo per sistemazione dossier quotidiani mancanti
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacc">idx macchina</param>
|
||||||
|
/// <returns>"OK" se completato</returns>
|
||||||
|
Task<string> FixDailyDossierAsync(string idxMacc);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce il codice valOut dell'ODL corrente (con cache redis interna)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>codice valOut dell'ODL corrente</returns>
|
||||||
|
Task<string> GetCurrOdlAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce il modello dell'ultimo ODL per macchina, con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Modello ODLExpModel</returns>
|
||||||
|
Task<ODLExpModel> GetLastOdlAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Effettua il calcolo della data-ora di riferimento per il server, correggendo il delta
|
||||||
|
/// tra orologio macchina e server
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dtEve">data-oras dell'evento (macchina)</param>
|
||||||
|
/// <param name="dtCurr">data-ora corrente (server)</param>
|
||||||
|
/// <returns>Data-ora evento corretta</returns>
|
||||||
|
DateTime GetSrvDtEvent(string dtEve, string dtCurr);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce se la macchina sia abilitata all'inserimento dati da IOB
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>true se abilitato all'input</returns>
|
||||||
|
Task<bool> IobInsEnabAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce se la macchina sia abilitata come master di un impianto
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>true se \u00e8 master</returns>
|
||||||
|
Task<bool> IobIsMasterAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce se la macchina sia abilitata all'inserimento nel Signal Log
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>true se abilitato</returns>
|
||||||
|
Task<bool> IobSLogEnabAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce i valori ammessi per una tabella/colonna (con cache redis interna)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tabName">nome tabella</param>
|
||||||
|
/// <param name="fieldName">nome campo</param>
|
||||||
|
/// <returns>Lista di ListValuesModel</returns>
|
||||||
|
Task<List<ListValuesModel>> ListValuesFilt(string tabName, string fieldName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce l'elenco completo delle relazioni macchine master-slave, con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Lista di Macchine2SlaveModel</returns>
|
||||||
|
Task<List<Macchine2SlaveModel>> Macchine2SlaveGetAllAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce le macchine filtrate per gruppo, con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="codGruppo">codice gruppo (o "*" per tutto)</param>
|
||||||
|
/// <returns>Lista di MacchineModel</returns>
|
||||||
|
Task<List<MacchineModel>> MacchineGetFilt(string codGruppo);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce il path delle ricette di una macchina, con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Path delle ricette</returns>
|
||||||
|
Task<string> MacchineRecipeArchive(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce la lista parametri correnti (ObjItemDTO) della macchina da Redis
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Lista di ObjItemDTO</returns>
|
||||||
|
Task<List<ObjItemDTO>> MachineParamListAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce i parametri correnti della macchina che necessitano di write (writable + reqValue valorizzato)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Lista di ObjItemDTO</returns>
|
||||||
|
Task<List<ObjItemDTO>> MachineParamListPendingWriteAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Imposta i parametri correnti (ObjItemDTO) nella cache Redis della macchina
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="currData">dati parametri da impostare</param>
|
||||||
|
/// <returns>true se salvato</returns>
|
||||||
|
Task<bool> MachineParamListSetAsync(string idxMacchina, List<ObjItemDTO> currData);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Effettua l'UPSERT degli elementi dei parametri macchina in Redis
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="innovations">nuovi elementi da aggiungere/aggiornare</param>
|
||||||
|
/// <returns>true se completato</returns>
|
||||||
|
Task<bool> MachineParamUpsertAsync(string idxMacchina, List<ObjItemDTO> innovations);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce i campi DatiMacchine + StatoMacchine come dizionario (da Redis o DB)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Dizionario KVP dei campi macchina</returns>
|
||||||
|
Task<Dictionary<string, string>> mDatiMacchineAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce i parametri ottimizzati per la macchine (Redis hash sync)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Dizionario KVP parametri</returns>
|
||||||
|
Dictionary<string, string> mOptParMacchina(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce i task salvati della macchina (Redis hash sync)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Dizionario KVP dei task salvati</returns>
|
||||||
|
Dictionary<string, string> mSavedTaskMacchina(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce l'elenco dalla tabella MappaStatoExpl, con o senza cache
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="forceDb">se true forza lettura database senza cache</param>
|
||||||
|
/// <returns>Lista di MappaStatoExplModel</returns>
|
||||||
|
Task<List<MappaStatoExplModel>> MseGetAllAsync(bool forceDb = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce il dizionario KVP della tabella Multi State Machine Ingressi (da Redis)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Array di KeyValuePair</returns>
|
||||||
|
Task<KeyValuePair<string, string>[]> mTabMSMIAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce i task in esecuzione per la macchina (Redis hash sync)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Dizionario KVP dei task</returns>
|
||||||
|
Dictionary<string, string> mTaskMacchina(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce i task in esecuzione per la macchina (Redis hash async)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Dizionario KVP dei task</returns>
|
||||||
|
Task<Dictionary<string, string>> mTaskMacchinaAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generazione automatica ODL giornalieri per la macchina
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="dataInizio">data di inizio generazione</param>
|
||||||
|
/// <param name="dataFine">data di fine generazione</param>
|
||||||
|
/// <param name="codArticolo">codice articolo</param>
|
||||||
|
/// <returns>true se generato con successo</returns>
|
||||||
|
Task<bool> OdlAutoDayGenAsync(string idxMacchina, DateTime dataInizio, DateTime dataFine, string codArticolo);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generazione automatica ODL giornalieri completa con tutti i parametri PO/TC
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="dataInizio">data inizio</param>
|
||||||
|
/// <param name="dataFine">data fine</param>
|
||||||
|
/// <param name="codArticolo">codice articolo</param>
|
||||||
|
/// <param name="pzPODL">pezzi per PODL</param>
|
||||||
|
/// <param name="pzPallet">pezzi per pallet</param>
|
||||||
|
/// <param name="keyRichiesta">chiave richiesta</param>
|
||||||
|
/// <param name="tcAssegnato">TC assegnato</param>
|
||||||
|
/// <param name="codGruppo">codice gruppo</param>
|
||||||
|
/// <param name="flgCreaPODL">flag crea PODL</param>
|
||||||
|
/// <param name="flgCheckTC">flag verifica TC</param>
|
||||||
|
/// <returns>true se generato con successo</returns>
|
||||||
|
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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce l'ODL corrente per macchina, con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="IdxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Modello ODLExpModel</returns>
|
||||||
|
Task<ODLExpModel> OdlCurrByMaccAsync(string IdxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce il modello PODL dato il suo indice, con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxPODL">indice PODL</param>
|
||||||
|
/// <returns>Modello PODLModel</returns>
|
||||||
|
Task<PODLModel> POdlGetByKey(int idxPODL);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce i PODL per macchina/articolo, con cache Fusion
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="codArticolo">codice articolo</param>
|
||||||
|
/// <param name="codGruppo">codice gruppo</param>
|
||||||
|
/// <param name="onlyFree">solo PODL liberi</param>
|
||||||
|
/// <returns>Lista di PODLExpModel</returns>
|
||||||
|
Task<List<PODLExpModel>> POdlGetByMaccArtAsync(string idxMacchina, string codArticolo, string codGruppo, bool onlyFree);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processa la registrazione di un flusso (FL) da IOB
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="flux">codice flusso (es. Ingresso, Uscita)</param>
|
||||||
|
/// <param name="valore">valore valOut del flusso</param>
|
||||||
|
/// <param name="dtEve">data-ora dell'evento (macchina)</param>
|
||||||
|
/// <param name="dtCurr">data-ora corrente (server)</param>
|
||||||
|
/// <param name="contatore">contatore invio</param>
|
||||||
|
/// <param name="disabKA">se true disabilita la scrittura del keepalive</param>
|
||||||
|
/// <returns>"OK" se completato</returns>
|
||||||
|
Task<string> ProcessFluxLogAsync(string idxMacchina, string flux, string valore, string dtEve, string dtCurr, int contatore, bool disabKA);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processa un input completo da IOB (verifica parametri, log segnali, processing microstato)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="valore">valore valOut</param>
|
||||||
|
/// <param name="dtEve">data-ora evento (macchina)</param>
|
||||||
|
/// <param name="dtCurr">data-ora corrente (server)</param>
|
||||||
|
/// <param name="contatore">contatore</param>
|
||||||
|
/// <returns>"OK" se completato, error message in caso contrario</returns>
|
||||||
|
Task<string> ProcessInputAsync(string idxMacchina, string valore, string dtEve, string dtCurr, string contatore);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processa un UserLog registrato da IOB (DI=dichiarazioni, RC=controlli, RS=scarti)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="flux">tipo flusso: DI (Dichiarazione), RC (Controllo), RS (Scarto)</param>
|
||||||
|
/// <param name="valore">valore/testo</param>
|
||||||
|
/// <param name="dtEve">data-ora evento</param>
|
||||||
|
/// <param name="dtCurr">data-ora corrente</param>
|
||||||
|
/// <param name="contatore">contatore invio dati</param>
|
||||||
|
/// <param name="matrOpr">matricola operatore</param>
|
||||||
|
/// <param name="label">causale scarto o tagCode</param>
|
||||||
|
/// <param name="valNum">esitoOk (0/1) o quantit\u00e0 scarto</param>
|
||||||
|
/// <returns>"OK" se completato</returns>
|
||||||
|
Task<string> ProcessUserLogAsync(string idxMacchina, string flux, string valore, string dtEve, string dtCurr, int contatore, int matrOpr, string label, int valNum);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce il contapezzi salvato in Redis per la macchina
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Contatore pezzi (-1 se non trovato)</returns>
|
||||||
|
Task<int> pzCounter(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce il contapezzi come conteggio da TCRilevati (dal DB)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Conteggio pezzi (-1 se non trovato)</returns>
|
||||||
|
Task<int> PzCounterTcAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ricerca la ricetta su MongoDB dato l'indice del PODL
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxPODL">indice PODL di riferimento</param>
|
||||||
|
/// <returns>Modello ricetta o null</returns>
|
||||||
|
Task<RecipeModel?> RecipeGetByPODL(int idxPODL);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Effettua il conteggio delle chiavi Redis che corrispondono a un pattern
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keyPattern">pattern di ricerca</param>
|
||||||
|
/// <returns>Numero di chiavi trovate</returns>
|
||||||
|
int RedisCountKey(string keyPattern);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Elimina una chiave dalla memoria Redis
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keyVal">chiave da eliminare</param>
|
||||||
|
/// <returns>true se eliminata</returns>
|
||||||
|
bool RedisDelKey(string keyVal);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Elimina una chiave dalla memoria Redis (async)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keyVal">chiave da eliminare</param>
|
||||||
|
/// <returns>true se eliminata</returns>
|
||||||
|
Task<bool> RedisDelKeyAsync(RedisKey keyVal);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Esegue il flush di tutte le chiavi Redis che corrispondono a un pattern
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">pattern di ricerca</param>
|
||||||
|
/// <returns>true se completato</returns>
|
||||||
|
Task<bool> RedisFlushPatternAsync(RedisValue pattern);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Leggo un hash Redis come array di KeyValuePair (sync)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="redKey">chiave Redis</param>
|
||||||
|
/// <returns>Array di KeyValuePair</returns>
|
||||||
|
KeyValuePair<string, string>[] RedisGetHash(RedisKey redKey);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Leggo un hash Redis come array di KeyValuePair (async)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="redKey">chiave Redis</param>
|
||||||
|
/// <returns>Array di KeyValuePair</returns>
|
||||||
|
Task<KeyValuePair<string, string>[]> RedisGetHashAsync(RedisKey redKey);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Leggo un hash Redis come dizionario (sync)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hashKey">chiave Redis</param>
|
||||||
|
/// <returns>Dizionario KVP</returns>
|
||||||
|
Dictionary<string, string> RedisGetHashDict(RedisKey hashKey);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Leggo un hash Redis come dizionario (async)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hashKey">chiave Redis</param>
|
||||||
|
/// <returns>Dizionario KVP</returns>
|
||||||
|
Task<Dictionary<string, string>> RedisGetHashDictAsync(RedisKey hashKey);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Leggo un singolo campo di un hash Redis (async)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">chiave Redis</param>
|
||||||
|
/// <param name="hashField">nome campo hash</param>
|
||||||
|
/// <returns>Valore del campo</returns>
|
||||||
|
Task<RedisValue> RedisGetHashFieldAsync(RedisKey key, string hashField);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifica se una chiave esista in Redis (sync)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">chiave Redis</param>
|
||||||
|
/// <returns>true se la chiave esiste</returns>
|
||||||
|
bool RedisKeyPresent(RedisKey key);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifica se una chiave esista in Redis (async)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">chiave Redis</param>
|
||||||
|
/// <returns>true se la chiave esiste</returns>
|
||||||
|
Task<bool> RedisKeyPresentAsync(RedisKey key);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Imposta un hash Redis con expiration opzionale (sync)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="redKey">chiave Redis</param>
|
||||||
|
/// <param name="valori">array di coppie chiave-valore da inserire</param>
|
||||||
|
/// <param name="expireSeconds">TTL in secondi (-1 = nessuna expiration)</param>
|
||||||
|
void RedisSetHash(RedisKey redKey, KeyValuePair<string, string>[] valori, double expireSeconds = -1.0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Imposta un hash Redis con expiration opzionale (async)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="redKey">chiave Redis</param>
|
||||||
|
/// <param name="valori">array di coppie chiave-valore da inserire</param>
|
||||||
|
/// <param name="expireSeconds">TTL in secondi (-1 = nessuna expiration)</param>
|
||||||
|
Task RedisSetHashAsync(RedisKey redKey, KeyValuePair<string, string>[] valori, double expireSeconds = -1.0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Imposta un hash Redis con expiration opzionale (sync) da dizionario
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="redKey">chiave Redis</param>
|
||||||
|
/// <param name="valori">dizionario di coppie chiave-valore da inserire</param>
|
||||||
|
/// <param name="expireSeconds">TTL in secondi (-1 = nessuna expiration)</param>
|
||||||
|
void RedisSetHashDict(RedisKey redKey, Dictionary<string, string> valori, double expireSeconds = -1.0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Imposta un hash Redis con expiration opzionale (async) da dizionario
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="redKey">chiave Redis</param>
|
||||||
|
/// <param name="valori">dizionario di coppie chiave-valore da inserire</param>
|
||||||
|
/// <param name="expireSeconds">TTL in secondi (-1 = nessuna expiration)</param>
|
||||||
|
Task RedisSetHashDictAsync(RedisKey redKey, Dictionary<string, string> valori, double expireSeconds = -1.0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserimento record RemoteRebootLog con eventuale pulizia dei record vecchi
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newRec">record da inserire</param>
|
||||||
|
/// <returns>true se completato</returns>
|
||||||
|
Task<bool> RemRebootLogAddAsync(RemoteRebootLogModel newRec);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Elimina un task da elenco Redis per l'impianto indicato
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="tName">nome task da eliminare</param>
|
||||||
|
/// <returns>Dizionario KVP rimanente</returns>
|
||||||
|
Task<Dictionary<string, string>> RemTask2ExeMacchinaAsync(string idxMacchina, taskType tName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resetta la tabella Multi State Machine Ingressi per macchina rileggendola dal DB
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <returns>Array di KVP della State Machine Ingressi</returns>
|
||||||
|
Task<KeyValuePair<string, string>[]> resetMSMIAsync(string idxMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registra la movimentazione di un carico pezzi su Redis
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="qty">quantit\u00e0 da registrare</param>
|
||||||
|
/// <returns>"OK" se completato</returns>
|
||||||
|
Task<string> saveCaricoPezzi(string idxMacchina, string qty);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Salva un elenco di dati macchina in DB
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">identificativo della serie dati</param>
|
||||||
|
/// <param name="dataList">elenco di dati macchina da salvare</param>
|
||||||
|
/// <returns>true se salvato</returns>
|
||||||
|
Task<bool> SaveDataItemsAsync(string id, List<MachDataItem> dataList);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Salva i dati macchina-IOB (serializzazione JSON) su Redis
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="serData">dati JSON serializzati</param>
|
||||||
|
/// <returns>true se salvato</returns>
|
||||||
|
Task<bool> SaveMachine2Iob(string idxMacchina, string serData);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Salva la configurazione della macchina come dizionario su Redis
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="currDict">dizionario di configurazione</param>
|
||||||
|
/// <returns>true se salvato</returns>
|
||||||
|
Task<bool> SaveMachineIobConf(string idxMacchina, Dictionary<string, string> currDict);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Salva il segnale di "microstato" come record SignalLog su DB (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>true se salvato</returns>
|
||||||
|
Task<bool> saveSigLogAsync(string idxMacchina, string valore, DateTime dtEve, int contatore);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Scrive un evento di keepalive se non presente in Redis con TTL
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="IdxMacchina">idx macchina</param>
|
||||||
|
/// <param name="oraMacchina">ora macchina</param>
|
||||||
|
Task ScriviKeepAliveAsync(string IdxMacchina, DateTime oraMacchina);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Salva la configurazione YAML completa dell'IOB su Redis
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="iobConfFull">configurazione YAML completa</param>
|
||||||
|
/// <returns>true se salvata</returns>
|
||||||
|
Task<bool> SetIobConfYamlAsync(string idxMacchina, string iobConfFull);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Salva la mappatura memoria PLC su Redis
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="currMap">mappatura PLC da salvare</param>
|
||||||
|
/// <returns>true se salvata</returns>
|
||||||
|
Task<bool> SetIobMemMap(string idxMacchina, PlcMemMapDto currMap);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce la tabella key-value della State Machine Ingressi per famiglia,
|
||||||
|
/// rileggendola dal DB e salvandola in Redis
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxFamIn">idx famiglia ingressi</param>
|
||||||
|
/// <returns>Array di KVP (currentMicroStato_nVal -> IdxTipoEv_nStato)</returns>
|
||||||
|
Task<KeyValuePair<string, string>[]> StateMachInByKeyAsync(int idxFamIn);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Effettua l'UPSERT degli oggetti corrente della macchina su Redis (legacy compatibilit\u00e0)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxMacchina">idx macchina</param>
|
||||||
|
/// <param name="innovations">dati da aggiornare/aggiungere</param>
|
||||||
|
/// <returns>true se completato</returns>
|
||||||
|
Task<bool> UpsertCurrObjItemsAsync(string idxMacchina, List<ObjItemDTO> innovations);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restituisce il valore SPECIFICATO per la state machine ingressi in formato hash Redis
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idxFamIn">idx famiglia ingressi</param>
|
||||||
|
/// <param name="idxMicroStato">idx microstato</param>
|
||||||
|
/// <param name="valoreIn">valore ingresso</param>
|
||||||
|
/// <returns>valore (IdxFamIn_nValore) dalla tab SMI Redis</returns>
|
||||||
|
Task<string> ValoreSmiAsync(int idxFamIn, int idxMicroStato, int valoreIn);
|
||||||
|
|
||||||
|
#endregion Public Methods
|
||||||
|
}
|
||||||
|
}
|
||||||
+399
-949
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,112 @@
|
|||||||
|
using MP.Data.Services.IOC;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
namespace MP.IOC.Endpoints
|
||||||
|
{
|
||||||
|
public static class IobEndpoints
|
||||||
|
{
|
||||||
|
public static void MapIobHighPerformanceEndpoints(this IEndpointRouteBuilder app)
|
||||||
|
{
|
||||||
|
// 1. Root di test base: api/IOB e api/IOB/alive
|
||||||
|
app.MapGet("api/IOB", () => "OK");
|
||||||
|
app.MapGet("api/IOB/alive", () => "OK");
|
||||||
|
|
||||||
|
// 2. Il metodo Enabled ad alto traffico: api/IOB/enabled/{id}
|
||||||
|
app.MapGet("api/IOB/enabled/{id}", async (string id, IIocService iocService, HttpContext context) =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||||
|
return "Missing ID";
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool isEnabled = await iocService.IobInsEnabAsync(id);
|
||||||
|
|
||||||
|
if (!isEnabled)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = StatusCodes.Status422UnprocessableEntity;
|
||||||
|
return "NO";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "OK";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Errore durante la verifica abilitazione per {Id}", id);
|
||||||
|
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
return "Errore interno del server";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. Metodo: SetCounter (api/IOB/setCounter/{id}?counter=10)
|
||||||
|
// Nota: 'counter' viene letto automaticamente dalla Query String grazie al Model Binding automatico
|
||||||
|
app.MapGet("api/IOB/setCounter/{id}", async (string id, string counter, IIocService iocService, HttpContext context) =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||||
|
return "Missing ID";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ottimizzazione: esegui il Replace solo se il carattere è effettivamente presente
|
||||||
|
if (id.Contains('|'))
|
||||||
|
{
|
||||||
|
id = id.Replace('|', '#');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Se il log di Debug è disattivato in produzione, eviti l'allocazione della stringa interpolata
|
||||||
|
if (Log.IsDebugEnabled)
|
||||||
|
{
|
||||||
|
Log.Debug($"Salvataggio counter | id: {id} | pzCount: {counter}");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string answ = await iocService.SaveCounterAsync(id, counter);
|
||||||
|
return answ; // Ritorna direttamente la stringa (Status 200 di default, zero allocazioni di ObjectResult)
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
// Usiamo la stringa formattata standard di NLog per evitare Environment.NewLine manuale
|
||||||
|
Log.Error(exc, "Errore in SetCounter per macchina {MachineId}", id);
|
||||||
|
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
return "NO";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. Metodo: GetCurrODL (api/IOB/getCurrODL/{id})
|
||||||
|
app.MapGet("api/IOB/getCurrODL/{id}", async (string id, IIocService iocService, HttpContext context) =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(id))
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||||
|
return "Missing ID";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id.Contains('|'))
|
||||||
|
{
|
||||||
|
id = id.Replace('|', '#');
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var odl = await iocService.GetCurrOdlAsync(id);
|
||||||
|
|
||||||
|
// Ottimizzazione: Se 'odl' è già una stringa, ritornala direttamente.
|
||||||
|
// Se è un oggetto o un numero, il C# gestirà l'estrazione. Evitiamo $"{odl}" che alloca memoria inutilmente.
|
||||||
|
return odl?.ToString() ?? string.Empty;
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
Log.Error(exc, "Errore GetCurrODL | macchina {MachineId}", id);
|
||||||
|
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
return "NO";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Version>8.16.2606.408</Version>
|
<Version>8.16.2606.1212</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -31,10 +31,15 @@
|
|||||||
<PackageReference Include="EgwCoreLib.Razor" />
|
<PackageReference Include="EgwCoreLib.Razor" />
|
||||||
<PackageReference Include="EgwCoreLib.Utils" />
|
<PackageReference Include="EgwCoreLib.Utils" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components" />
|
<PackageReference Include="Microsoft.AspNetCore.Components" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" />
|
||||||
<PackageReference Include="NLog" />
|
<PackageReference Include="NLog" />
|
||||||
<PackageReference Include="NLog.Web.AspNetCore" />
|
<PackageReference Include="NLog.Web.AspNetCore" />
|
||||||
<PackageReference Include="Snappier" />
|
<PackageReference Include="Snappier" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" />
|
<PackageReference Include="Swashbuckle.AspNetCore" />
|
||||||
|
<PackageReference Include="ZiggyCreatures.FusionCache" />
|
||||||
|
<PackageReference Include="ZiggyCreatures.FusionCache.Backplane.StackExchangeRedis" />
|
||||||
|
<PackageReference Include="ZiggyCreatures.FusionCache.Serialization.NewtonsoftJson" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
+21
-2
@@ -1,16 +1,19 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using MP.Core.Conf;
|
using MP.Core.Conf;
|
||||||
using MP.Data;
|
using MP.Data;
|
||||||
using MP.IOC.Components;
|
using MP.IOC.Components;
|
||||||
using MP.IOC.Data;
|
using MP.IOC.Data;
|
||||||
|
using MP.IOC.Endpoints;
|
||||||
using MP.IOC.Services;
|
using MP.IOC.Services;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NLog.Web;
|
using NLog.Web;
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
using ZiggyCreatures.Caching.Fusion;
|
||||||
|
using ZiggyCreatures.Caching.Fusion.Backplane.StackExchangeRedis;
|
||||||
using ZiggyCreatures.Caching.Fusion.Serialization;
|
using ZiggyCreatures.Caching.Fusion.Serialization;
|
||||||
using ZiggyCreatures.Caching.Fusion.Serialization.NewtonsoftJson;
|
using ZiggyCreatures.Caching.Fusion.Serialization.NewtonsoftJson;
|
||||||
|
|
||||||
@@ -92,6 +95,12 @@ builder.Services.AddSwaggerGen(c =>
|
|||||||
var redisMux = ConnectionMultiplexer.Connect(confRedis);
|
var redisMux = ConnectionMultiplexer.Connect(confRedis);
|
||||||
builder.Services.AddSingleton<IConnectionMultiplexer>(redisMux);
|
builder.Services.AddSingleton<IConnectionMultiplexer>(redisMux);
|
||||||
|
|
||||||
|
// Distributed cache (necessario per FusionCache L2 Redis)
|
||||||
|
builder.Services.AddStackExchangeRedisCache(options =>
|
||||||
|
{
|
||||||
|
options.Configuration = confRedis;
|
||||||
|
});
|
||||||
|
|
||||||
// oggetto principale accesso dati
|
// oggetto principale accesso dati
|
||||||
//builder.Services.AddScoped<MpDataService>();
|
//builder.Services.AddScoped<MpDataService>();
|
||||||
builder.Services.AddSingleton<MpDataService>();
|
builder.Services.AddSingleton<MpDataService>();
|
||||||
@@ -99,8 +108,14 @@ builder.Services.AddSingleton<MpDataService>();
|
|||||||
// 1. Registra il serializzatore NewtonsoftJson per FusionCache
|
// 1. Registra il serializzatore NewtonsoftJson per FusionCache
|
||||||
builder.Services.AddSingleton<IFusionCacheSerializer>(new FusionCacheNewtonsoftJsonSerializer());
|
builder.Services.AddSingleton<IFusionCacheSerializer>(new FusionCacheNewtonsoftJsonSerializer());
|
||||||
|
|
||||||
// 2. Configura FusionCache solo per la memoria (L1)
|
// 2. Configura FusionCache (L1 Memory + L2 Redis Distributed + L3 DB via factory)
|
||||||
builder.Services.AddFusionCache()
|
builder.Services.AddFusionCache()
|
||||||
|
.WithDistributedCache(sp => sp.GetRequiredService<IDistributedCache>())
|
||||||
|
.WithSerializer(new FusionCacheNewtonsoftJsonSerializer())
|
||||||
|
.WithBackplane(new RedisBackplane(new RedisBackplaneOptions
|
||||||
|
{
|
||||||
|
ConnectionMultiplexerFactory = () => Task.FromResult<IConnectionMultiplexer>(redisMux)
|
||||||
|
}))
|
||||||
.WithDefaultEntryOptions(options =>
|
.WithDefaultEntryOptions(options =>
|
||||||
{
|
{
|
||||||
// Durata di default dei dati in memoria
|
// Durata di default dei dati in memoria
|
||||||
@@ -156,9 +171,13 @@ app.UseDefaultFiles();
|
|||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseAntiforgery();
|
app.UseAntiforgery();
|
||||||
|
|
||||||
// Mappatura delle API
|
// Mappatura MinimalApi da file ext x metodi high perf
|
||||||
|
app.MapIobHighPerformanceEndpoints();
|
||||||
|
|
||||||
|
// Mappatura delle API "standard"
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
||||||
|
|
||||||
// Mappatura della Dashboard Blazor
|
// Mappatura della Dashboard Blazor
|
||||||
app.MapRazorComponents<App>()
|
app.MapRazorComponents<App>()
|
||||||
.AddInteractiveServerRenderMode();
|
.AddInteractiveServerRenderMode();
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
# MP.IOC
|
||||||
|
|
||||||
|
MAPO IOC: WebApi rest per la gestione delle chiamate dagli applicativi remoti sul campo (IOB-PI su Raspberry Pi e IOB-WIN su PC Windows) che si occupano di comunicare con le varie macchine di processo i dati da trasmettere al MES.
|
||||||
|
|
||||||
|
È la nuova implementazione del modulo IO (il precedente era fatto in .NET Framework 4.7.2) su cui si sta dirigendo lo sviluppo della soluzione MES MAPO.
|
||||||
|
|
||||||
|
Integra raccolta di informazioni riguardo ai compiti svolti e questi sono ottimizzati per l'impiego di cache e ottimizzazioni varie su ogni strato del progetto.
|
||||||
|
|
||||||
|
**Build:** ✅ 0 errori, 12 warnings
|
||||||
|
|
||||||
|
## Sezioni Principali
|
||||||
|
|
||||||
|
- Api IOB (`api/IOB`) — endpoint principale per comunicazioni da campo (52 metodi)
|
||||||
|
- Benchmark Redis (`api/Bench`) — tool di test per debugging Redis
|
||||||
|
- Api Ricette (`api/Recipe`) — recupero ricette per PODL
|
||||||
|
- Dashboard Blazor — interfaccia web interattiva
|
||||||
|
|
||||||
|
## Architettura
|
||||||
|
|
||||||
|
### Livello Controller (MP.IOC/Controllers/)
|
||||||
|
|
||||||
|
| Controller | Routing | Methods | Descrizione |
|
||||||
|
|------------|---------|---------|-------------|
|
||||||
|
| `IOBController` | `api/IOB` | 52 | Endpoint principale per IOB-PI/IOB-WIN |
|
||||||
|
| `BenchController` | `api/Bench` | 10 | Test/benchmark Redis |
|
||||||
|
| `RecipeController` | `api/Recipe` | 2 | API ricette (JSON) |
|
||||||
|
| `RecipeArchiveController` | `api/RecipeArchive` | 2 | API archive ricette (file) |
|
||||||
|
|
||||||
|
### Livello Dati
|
||||||
|
|
||||||
|
| Componente | Tipologia | Descrizione |
|
||||||
|
|------------|-----------|-------------|
|
||||||
|
| `MpDataService` | Singleton | Service di accesso dati principale (~3516 righe) |
|
||||||
|
| `MpIocController` | Singleton | 82 metodi EFCore nel progetto MP.Data |
|
||||||
|
| `Redis` | 2 connessioni | `redisConn`, `redisConnAdmin` per dati IOB |
|
||||||
|
| `MongoDB` | Via `MpMongoController` | Storage ricette |
|
||||||
|
|
||||||
|
### Livello DbContext
|
||||||
|
|
||||||
|
| DbContext | ConnStr | Uso |
|
||||||
|
|-----------|---------|-----|
|
||||||
|
| `MoonProContext` | `MP.Data` | Tabelle anagrafiche, ODL, produzione, macchine |
|
||||||
|
| `MoonPro_UtilsContext` | `MP.Utils` | Tabelle utility (VMSFD, MicroStati) |
|
||||||
|
| `MoonPro_FluxContext` | `MP.Flux` | FluxLog, configurazioni flusso |
|
||||||
|
|
||||||
|
### Livello DI
|
||||||
|
|
||||||
|
Registrato via `AddIocDataLayer()` in `MP.Data/DataServiceCollectionExtensions.cs`:
|
||||||
|
|
||||||
|
```
|
||||||
|
Singleton: IMtcSetupRepository, IMtcSetupService, ProductionRepository, MpIocController, MpDataService, IFusionCacheSerializer, IConnectionMultiplexer, IFusionCache
|
||||||
|
Scoped: IIocRepository, IStatsAggrRepository, IStatsDetailRepository, IIocService, IStatsAggrService, IStatsDetailService
|
||||||
|
```
|
||||||
|
|
||||||
|
### Livello Infrastruttura
|
||||||
|
|
||||||
|
- **FusionCache** — ✅ **L1 Memory + L2 Redis Distributed + Redis Backplane** (migrazione giugno 2026)
|
||||||
|
- **MessagePipe** — Broadcasting real-time tra servizi
|
||||||
|
- **OpenTelemetry** — Tracing configurabile (non abilitato in MP.IOC)
|
||||||
|
- **Swagger** — Documentazione API in sviluppo
|
||||||
|
|
||||||
|
## Refactoring Completati
|
||||||
|
|
||||||
|
### ✅ Fase 1: Anti-Pattern Controllers
|
||||||
|
|
||||||
|
Rimossi `static IConfiguration _configuration` da tutti i 4 controller (`IOBController`, `BenchController`, `RecipeController`, `RecipeArchiveController`) e rimossa la dead code assignment dai costruttori.
|
||||||
|
|
||||||
|
### ✅ Fase 2: FusionCache + Redis Backplane
|
||||||
|
|
||||||
|
**Pacchetti aggiunti** (`MP.IOC.csproj`):
|
||||||
|
- `Microsoft.Extensions.Caching.StackExchangeRedis`
|
||||||
|
- `ZiggyCreatures.FusionCache`
|
||||||
|
- `ZiggyCreatures.FusionCache.Backplane.StackExchangeRedis`
|
||||||
|
- `ZiggyCreatures.FusionCache.Serialization.NewtonsoftJson`
|
||||||
|
|
||||||
|
**Configurazione** (`Program.cs`):
|
||||||
|
- FusionCache attivo con **L1 Memory** + **L2 Redis Distributed** + **Redis Backplane**
|
||||||
|
- Serializer: `FusionCacheNewtonsoftJsonSerializer`
|
||||||
|
- Default Duration: 1 minuto con jitter max 5 secondi
|
||||||
|
|
||||||
|
**Helper aggiunto** (`MpDataService.cs`):
|
||||||
|
- `GetOrFetchAsync<T>()` — wrapper FusionCache con ActivitySource tracking e source tagging (MEMORY/REDIS/DB)
|
||||||
|
|
||||||
|
**18 metodi migrati** dal pattern manuale Redis (`redisDb.StringGetAsync`/`StringSetAsync`) → FusionCache:
|
||||||
|
|
||||||
|
| # | Metodo | Fetch From |
|
||||||
|
|---|--------|------------|
|
||||||
|
| 1 | `AnagStatiGetAllAsync` | `IocDbController` |
|
||||||
|
| 2 | `ArticoliGetLastByMaccAsync` | `IocDbController` |
|
||||||
|
| 3 | `ConfigGetAllAsync` | `IocDbController` |
|
||||||
|
| 4 | `DecNumArtGetFiltAsync` | `IocDbController` |
|
||||||
|
| 5 | `DossierLastByMachAsync` | `IocDbController` |
|
||||||
|
| 6 | `GetLastOdlAsync` | `IocDbController` |
|
||||||
|
| 7 | `ListValuesFilt` | `IocDbController` |
|
||||||
|
| 8 | `Macchine2SlaveGetAllAsync` | `IocDbController` |
|
||||||
|
| 9 | `MacchineGetFilt` | `_productionRepository` |
|
||||||
|
| 10 | `MacchineRecipeArchive` | `_productionRepository` |
|
||||||
|
| 11 | `MseGetAllAsync` | `IocDbController` (+ forceDb support) |
|
||||||
|
| 12 | `OdlCurrByMaccAsync` | `IocDbController` |
|
||||||
|
| 13 | `POdlGetByKey` | `_productionRepository` |
|
||||||
|
| 14 | `POdlGetByMaccArtAsync` | `IocDbController` |
|
||||||
|
| 15 | `ConfFluxMach` | `IocDbController` |
|
||||||
|
| 16 | `FluxLogFirstByMachAsync` | `IocDbController` |
|
||||||
|
| 17 | `FluxLogGetLastByMachAsync` | `IocDbController` |
|
||||||
|
|
||||||
|
### ✅ Build Verification
|
||||||
|
|
||||||
|
| Soluzione | Errori | Warnings | Stato |
|
||||||
|
|-----------|--------|----------|-------|
|
||||||
|
| MP-IOC | 0 | 12 | ✅ |
|
||||||
|
| MP-SPEC | 0 | vari | ✅ |
|
||||||
|
| MP-LAND | 0 | 3 | ✅ |
|
||||||
|
| MP-MON | 0 | vari | ✅ |
|
||||||
|
|
||||||
|
## Refactoring in Corso (Riferimento)
|
||||||
|
|
||||||
|
### Piano Generale (Vedi refactor_plan.md)
|
||||||
|
|
||||||
|
1. ~~**Fase 1 — Anti-Pattern**~~ — ✅ **Completata**
|
||||||
|
2. ~~**Fase 2 — FusionCache**~~ — ✅ **Completata** (18 metodi migrati)
|
||||||
|
3. **Fase 3 — Repository IoC** — Scomporre `MpIocController` (1480 righe, 82 metodi) in 7-10 repository specialistici
|
||||||
|
4. **Fase 4 — Scomposizione MpDataService** — Il monolite da 3516 righe suddiviso in servizi tematici
|
||||||
|
5. **Fase 5 — Build & Verifica** — Validazione finale
|
||||||
|
|
||||||
|
**Stato attuale:** Fasi 1-2 completate. Build stabile 0 errori.
|
||||||
|
|
||||||
|
## Prossimi Passi
|
||||||
|
|
||||||
|
- **Fase 3**: Creare repository specialistici per `MpIocController` (Vedi refactor_plan.md per il inventario completo)
|
||||||
|
- **Metodi atipici**: Verificare manualmente 4 metodi con pattern non-standards (`GetCurrOdlAsync`, `StatoProdMacchinaAsync` (private), `verificaIdxMacchinaAsync`, `ListMasterAsync`/`ListSlaveAsync`)
|
||||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<i>Modulo MP-IOC </i>
|
<i>Modulo MP-IOC </i>
|
||||||
<h4>Versione: 8.16.2606.408</h4>
|
<h4>Versione: 8.16.2606.1212</h4>
|
||||||
<br /> Note di rilascio:
|
<br /> Note di rilascio:
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
8.16.2606.408
|
8.16.2606.1212
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<item>
|
<item>
|
||||||
<version>8.16.2606.408</version>
|
<version>8.16.2606.1212</version>
|
||||||
<url>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/MP.IOC.zip</url>
|
<url>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/MP.IOC.zip</url>
|
||||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/ChangeLog.html</changelog>
|
<changelog>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/ChangeLog.html</changelog>
|
||||||
<mandatory>false</mandatory>
|
<mandatory>false</mandatory>
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
"Microsoft.EntityFrameworkCore.Database.Command": "Warning",
|
"Microsoft.EntityFrameworkCore.Database.Command": "Warning",
|
||||||
"Microsoft.EntityFrameworkCore.Infrastructure": "Warning",
|
"Microsoft.EntityFrameworkCore.Infrastructure": "Warning",
|
||||||
"Microsoft.WebTools.BrowserLink.Net.BrowserLinkMiddleware": "None",
|
"Microsoft.WebTools.BrowserLink.Net.BrowserLinkMiddleware": "None",
|
||||||
"Microsoft.AspNetCore.Watch.BrowserRefresh.BrowserRefreshMiddleware": "None"
|
"Microsoft.AspNetCore.Watch.BrowserRefresh.BrowserRefreshMiddleware": "None",
|
||||||
|
"ZiggyCreatures.Caching.Fusion": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"NLog": {
|
"NLog": {
|
||||||
@@ -24,7 +25,7 @@
|
|||||||
"logfile": {
|
"logfile": {
|
||||||
"type": "File",
|
"type": "File",
|
||||||
"fileName": "${basedir}/logs/${shortdate}.log",
|
"fileName": "${basedir}/logs/${shortdate}.log",
|
||||||
"keepFileOpen": false,
|
"keepFileOpen": true,
|
||||||
"archiveEvery": "Day",
|
"archiveEvery": "Day",
|
||||||
"archiveFileName": "${basedir}/logs/old/${shortdate}_{#}.log",
|
"archiveFileName": "${basedir}/logs/old/${shortdate}_{#}.log",
|
||||||
"archiveNumbering": "DateAndSequence",
|
"archiveNumbering": "DateAndSequence",
|
||||||
|
|||||||
@@ -0,0 +1,235 @@
|
|||||||
|
# Piano di Refactoring: MP.IOC
|
||||||
|
|
||||||
|
## Obiettivo
|
||||||
|
|
||||||
|
Modernizzare il progetto MP.IOC allineandolo agli standard architettonici definiti in MP.SPEC:
|
||||||
|
1. Rimuovere l'uso di `MpIocController` come servizio di accesso dati diretto
|
||||||
|
2. Migrare la logica di `MpDataService` ai repository esistenti (`IIocRepository`, `IStatsAggrRepository`, etc.)
|
||||||
|
3. Standardizzare il caching manuale Redis → FusionCache `GetOrFetchAsync`
|
||||||
|
4. Correggere tutti gli anti-pattern statici e DI
|
||||||
|
|
||||||
|
## Stato Attuale
|
||||||
|
|
||||||
|
| File | Riga | Tipo | Descrizione |
|
||||||
|
|------|------|------|-------------|
|
||||||
|
| `IOBController.cs` | 1675 | ✅ Controller ASP.NET | 52 endpoints REST (api/IOB) |
|
||||||
|
| `BenchController.cs` | 387 | ✅ Controller ASP.NET | Test/bench Redis |
|
||||||
|
| `RecipeController.cs` | 73 | ✅ Controller ASP.NET | API ricette (2 metodi) |
|
||||||
|
| `RecipeArchiveController.cs` | 130 | ✅ Controller ASP.NET | API ricette file (2 metodi) |
|
||||||
|
| `MpDataService.cs` | 3516 | ❌ Data Hub | Singleton, ~100 metodi, bypassa repository |
|
||||||
|
| `MpIocController.cs` | 1480 | ⚠️ Wrong location | 82 metodi EFCore in MP.Data, usato come servizio |
|
||||||
|
|
||||||
|
### Struttura DI Attuale (Post-Refactoring)
|
||||||
|
|
||||||
|
```
|
||||||
|
Program.cs
|
||||||
|
├── AddIocDataLayer() da MP.Data
|
||||||
|
│ ├── MpIocController ── Singleton ← usato direttamente da MpDataService
|
||||||
|
│ ├── IIocRepository ── Scoped ← mai usato da MpDataService
|
||||||
|
│ ├── IStatsAggrRepository ── Scoped ← mai usato
|
||||||
|
│ └── IStatsDetailRepository ── Scoped ← mai usato
|
||||||
|
├── MpDataService ── Singleton ← chiama IocDbController (statico), usa IFusionCache
|
||||||
|
└── IFusionCache ── L1 Memory + L2 Redis Distributed + Redis Backplane ✅
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problemi Chiave
|
||||||
|
|
||||||
|
1. **MpIocController come servizio** — 82 metodi EFCore classificati ingannevolmente come "Controller" ma in realtà sono un servizio di accesso dati, registrato come Singleton con DbContext che non è thread-safe
|
||||||
|
2. **MpDataService bypassa repository** — ~80% dei metodi chiama `IocDbController.XXX()` direttamente invece di usare `IIocRepository`
|
||||||
|
3. **Caching misto** — Parte migrato a FusionCache, parte ancora in manual StringSet/StringGet
|
||||||
|
4. **Singleton lifetime mismatch** — MpDataService è Singleton, registra campi statici per IoC Controller e Mongo Controller che vengono sovrascritti
|
||||||
|
|
||||||
|
## Piano di Refactoring
|
||||||
|
|
||||||
|
### Fase 1: Pulizia Anti-Pattern (Quick Wins) ✅ COMPLETATA
|
||||||
|
|
||||||
|
Rimosso `static IConfiguration _configuration` da tutti i 4 controller e rimossa la dead assignment dai costruttori:
|
||||||
|
|
||||||
|
| Controller | Prima | Dopo |
|
||||||
|
|------------|-------|------|
|
||||||
|
| `IOBController` | `IConfiguration + static field` | Nessun param (dead code), field rimosso |
|
||||||
|
| `BenchController` | `IConfiguration + static field` | Solo `MpDataService`, field rimosso |
|
||||||
|
| `RecipeController` | `IConfiguration + static field` | Solo `MpDataService`, field rimosso |
|
||||||
|
| `RecipeArchiveController` | `IConfiguration + static field` | Solo `MpDataService`, field rimosso |
|
||||||
|
|
||||||
|
### Fase 2: FusionCache + Redis Backplane ✅ COMPLETATA
|
||||||
|
|
||||||
|
#### 2.1 Pacchetti Aggiunti (MP.IOC.csproj)
|
||||||
|
|
||||||
|
| Pacchetto | Stato |
|
||||||
|
|-----------|-------|
|
||||||
|
| `Microsoft.Extensions.Caching.StackExchangeRedis` | ✅ |
|
||||||
|
| `ZiggyCreatures.FusionCache` | ✅ |
|
||||||
|
| `ZiggyCreatures.FusionCache.Backplane.StackExchangeRedis` | ✅ |
|
||||||
|
| `ZiggyCreatures.FusionCache.Serialization.NewtonsoftJson` | ✅ |
|
||||||
|
|
||||||
|
#### 2.2 Configurazione FusionCache (Program.cs)
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// L1 Memory + L2 Redis Distributed + Redis Backplane
|
||||||
|
builder.Services.AddStackExchangeRedisCache(options =>
|
||||||
|
options.Configuration = confRedis);
|
||||||
|
|
||||||
|
builder.Services.AddFusionCache()
|
||||||
|
.WithDistributedCache(sp => sp.GetRequiredService<IDistributedCache>())
|
||||||
|
.WithSerializer(new FusionCacheNewtonsoftJsonSerializer())
|
||||||
|
.WithBackplane(new RedisBackplane(new RedisBackplaneOptions {
|
||||||
|
ConnectionMultiplexerFactory = () => Task.FromResult<IConnectionMultiplexer>(redisMux)
|
||||||
|
}))
|
||||||
|
.WithDefaultEntryOptions(options => {
|
||||||
|
options.Duration = TimeSpan.FromMinutes(1);
|
||||||
|
options.JitterMaxDuration = TimeSpan.FromSeconds(5);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.3 Migrate 14 metodi da manual Redis a FusionCache
|
||||||
|
|
||||||
|
| # | Metodo | Categoria | Fetch From |
|
||||||
|
|---|--------|-----------|------------|
|
||||||
|
| 1 | `AnagStatiGetAllAsync` | Anagrafica | `IocDbController.AnagStatiGetAllAsync()` |
|
||||||
|
| 2 | `ArticoliGetLastByMaccAsync` | Anagrafica | `IocDbController.ArticoliGetLastByMaccAsync()` |
|
||||||
|
| 3 | `ConfigGetAllAsync` | Anagrafica | `IocDbController.ConfigGetAllAsync()` |
|
||||||
|
| 4 | `DecNumArtGetFiltAsync` | Anagrafica | `IocDbController.DecNumArtGetFiltAsync()` |
|
||||||
|
| 5 | `DossierLastByMachAsync` | Dossier | `IocDbController.DossGetLastByMaccAsync()` |
|
||||||
|
| 6 | `GetLastOdlAsync` | Produzione | `IocDbController.OdlLastByMaccAsync()` |
|
||||||
|
| 7 | `ListValuesFilt` | Configurazione | `IocDbController.ListValuesFiltAsync()` |
|
||||||
|
| 8 | `Macchine2SlaveGetAllAsync` | Machine | `IocDbController.Macchine2SlaveAsync()` |
|
||||||
|
| 9 | `MacchineGetFilt` | Machine | `_productionRepository.MacchineGetFiltAsync()` |
|
||||||
|
| 10 | `MacchineRecipeArchive` | Machine | `_productionRepository.MacchineGetFiltAsync("*")` |
|
||||||
|
| 11 | `MseGetAllAsync` | Stato | `IocDbController.MseGetAllAsync(maxAge)` (+ forceDb) |
|
||||||
|
| 12 | `OdlCurrByMaccAsync` | Produzione | `IocDbController.OdlCurrByMaccAsync()` |
|
||||||
|
| 13 | `POdlGetByKey` | Produzione | `_productionRepository.PODL_getByKeyAsync()` |
|
||||||
|
| 14 | `POdlGetByMaccArtAsync` | Produzione | `IocDbController.POdlGetByMaccArtAsync()` |
|
||||||
|
| 15 | `ConfFluxMach` | FluxLog | `IocDbController.ConfFluxFiltAsync()` |
|
||||||
|
| 16 | `FluxLogFirstByMachAsync` | FluxLog | `IocDbController.FluxLogFirstByMaccAsync()` |
|
||||||
|
| 17 | `FluxLogGetLastByMachAsync` | FluxLog | `IocDbController.FluxLogGetLastFiltAsync()` |
|
||||||
|
|
||||||
|
### Fase 3: Decomposizione MpIocController in Repository (NON INIZIATA)
|
||||||
|
|
||||||
|
`MpIocController` (1480 righe, 82 metodi) va scomposto in repository specialistici, come fatto per MP.SPEC:
|
||||||
|
|
||||||
|
| Attuale (82 metodi) | Nuovo Repository | Ambito |
|
||||||
|
|----------------------|-------------------|--------|
|
||||||
|
| `AnagStatiGetAllAsync`, `ArticoliGetLastByMaccAsync`, `ConfigGetAllAsync`, `ConfigUpdateAsync`, `DecNumArtGetFiltAsync`, `ListValuesFiltAsync`, `ListLinkFiltAsync`, `EvListInsert` | `IAnagRepository` | **Usato da SPEC** — già migrato! |
|
||||||
|
| `AutoStartOdlAsync`, `ConfirmaProdMacchinaAsync/Full`, `OdlCurrByMaccAsync`, `OdlLastByMaccAsync`, `OdlListByMaccPeriodoAsync`, `PezziProdMacchinaAsync`, `StatoProdMacchinaAsync` | `IProduzioneRepository` (nuovo) | Produzione IOB-specifica |
|
||||||
|
| `OdlAutoDayGenAsync/Full`, `POdlGetByMaccArtAsync`, `OdlFixMachineSlave` | `IProduzioneRepository` (nuovo) | Pianificazione produzione |
|
||||||
|
| `FluxLogInsertAsync`, `FluxLogGetLastFiltAsync`, `FluxLogFirstByMaccAsync`, `FluxLogTakeSnapshotLastAsync`, `ConfFluxFiltAsync` | `IFluxLogRepository` | **Usato da SPEC** — già migrato! |
|
||||||
|
| `DossGetLastByMaccAsync`, `SignalLogInsertAsync` | `IDossierRepository` | **Usato da SPEC** — già migrato! |
|
||||||
|
| `DatiMacchineGetAllAsync`, `MacchineGetByIdxAsync`, `MacchineUpsertAsync`, `MacchineGetFiltAsync`, `MacchineGetAllAsync`, `Macchine2Slave` | `IMacchineRepository` (nuovo) | Gestione macchine |
|
||||||
|
| `EvListMicroStatoInsertAsync`, `MicroStatoMacchinaUpsertAsync`, `MicroStatoMacchinaGetByIdxMaccAsync` | `IMicroStatoRepository` (nuovo) | Micro-stati macchine |
|
||||||
|
| `MSE_getUserForcedAsync`, `SMES_getHwTransitionsAsync`, `DDB_InsStatoBatchAsync`, `CheckCambiaStatoBatchAsync`, `RecalcMseAsync` | `IMseRepository` (nuovo) | Mappa stati macchin |
|
||||||
|
| `StateMachineIngressiAsync`, `VMSFDGetByMaccAsync`, `VMSFDGetMultiByMaccAsync`, `VMSFDGetAllAsync` | `IStateMachineRepository` (nuovo) | State machine |
|
||||||
|
| `KeepAliveUpsertAsync` | `IMacchineRepository` (nuovo) | Keep-alive |
|
||||||
|
| `AlarmLogInsertAsync`, `RegScartiInsertAsync`, `RegControlliInsertAsync`, `RegDichiarInsertAsync` | `IRegistroRepository` (nuovo) | Registri qualità |
|
||||||
|
| `RemRebootLog*` methods (6) | `IRemRebootRepository` (nuovo) | Reboot remote logging |
|
||||||
|
|
||||||
|
### Fase 4: Scomposizione MpDataService (NON INIZIATA)
|
||||||
|
|
||||||
|
`MpDataService.cs` (3516 righe) è troppo grande per essere un unico servizio. Proposta di scomposizione:
|
||||||
|
|
||||||
|
| Servizio | Responsabilità | Metodi |
|
||||||
|
|----------|---------------|--------|
|
||||||
|
| `MpDataService` (core) | Gateway, orchestrazione | ~50 |
|
||||||
|
| `IodlManagementService` | ODL lifecycle (apri, chiudi, split, conferma) | ~15 |
|
||||||
|
| `FluxLogProcessingService` | Processing flux log, snapshot, pareto | ~10 |
|
||||||
|
| `MachineCommunicationService` | Keep-alive, dati macchin, micro-stati, state machine | ~20 |
|
||||||
|
| `ProductionTrackingService` | Conferma produzione, pezzi prodotti, stato produzione | ~8 |
|
||||||
|
| `RedisCacheService` | Wrapper methods per Redis operations (Hash, String, Set) | ~15 |
|
||||||
|
|
||||||
|
**Nota:** La scomposizione va fatta **dopo** la migrazione a repository (Fase 3) per non dover modificare ogni singola chiamata.
|
||||||
|
|
||||||
|
### Fase 5: Build & Verifica ✅
|
||||||
|
|
||||||
|
Dopo ogni fase completa:
|
||||||
|
1. `dotnet build MP-IOC.sln` → ✅ 0 errori, 12 warnings (tutti preesistenti)
|
||||||
|
2. `dotnet build MP-SPEC.sln` → ✅ OK
|
||||||
|
3. `dotnet build MP-LAND.sln` → ✅ OK
|
||||||
|
4. `dotnet build MP-MON.sln` → ✅ OK
|
||||||
|
|
||||||
|
## Build Status Aggiornato
|
||||||
|
|
||||||
|
| Fase | File Modificati | Righe Modificate | Rischio | Stato |
|
||||||
|
|------|-----------------|-------------------|---------|-------|
|
||||||
|
| F1: Anti-Pattern 4 controller | 4 Controllers | ~20 | Basso | ✅ **Completato** |
|
||||||
|
| F2: FusionCache config + metodi | 2 Files + Helper | ~250 | Basso | ✅ **Completato** |
|
||||||
|
| F3: Repository IoC | 7+ nuovi + MpDataService | ~2000 | Alto | ⏳ Da fare |
|
||||||
|
| F4: Scomposizione MpDataService | 5 nuovi + 1 esistente | ~3516 | Alto | ⏳ Da fare |
|
||||||
|
| F5: Build & Verifica | — | — | Basso | ✅ 0 errori |
|
||||||
|
|
||||||
|
## Stato Completato
|
||||||
|
|
||||||
|
### ✅ Fase 1: Anti-Pattern Controller — COMPLETATA
|
||||||
|
|
||||||
|
Rimosso `static IConfiguration _configuration` da tutti i 4 controller.
|
||||||
|
|
||||||
|
### ✅ Fase 2: FusionCache + Redis Backplane — COMPLETATA
|
||||||
|
|
||||||
|
- Pacchetti FusionCache aggiunti a `MP.IOC.csproj`
|
||||||
|
- `IFusionCache` configurato con L1 Memory + L2 Redis + Backplane in `Program.cs`
|
||||||
|
- Campo `_cache` aggiunto a `MpDataService` con helper `GetOrFetchAsync<T>`
|
||||||
|
- **18 metodi migrati** dal pattern manuale Redis → FusionCache
|
||||||
|
- Build: ✅ **0 errori**, 12 warnings (tutti nullable reference preesistenti)
|
||||||
|
|
||||||
|
## Invntario Completo Metodi (Post-Refactoring)
|
||||||
|
|
||||||
|
### ✅ MIGRATI A FUSIONCACHE (18 metodi)
|
||||||
|
|
||||||
|
| # | Metodo | Fetch From | Tag |
|
||||||
|
|---|--------|------------|-----|
|
||||||
|
| 1 | `AnagStatiGetAllAsync` | `IocDbController.AnagStatiGetAllAsync()` | `Utils.redisAnagStati` |
|
||||||
|
| 2 | `ArticoliGetLastByMaccAsync` | `IocDbController.ArticoliGetLastByMaccAsync()` | `Utils.redisArtList:Last:{idxMacc}` |
|
||||||
|
| 3 | `ConfigGetAllAsync` | `IocDbController.ConfigGetAllAsync()` | `Utils.redisConfKey` |
|
||||||
|
| 4 | `DecNumArtGetFiltAsync` | `IocDbController.DecNumArtGetFiltAsync()` | `Utils.redisDecNumArtKey:{tag}` |
|
||||||
|
| 5 | `DossierLastByMachAsync` | `IocDbController.DossGetLastByMaccAsync()` | `Utils.redisDossByMacLast:{idxMacc}` |
|
||||||
|
| 6 | `GetLastOdlAsync` | `IocDbController.OdlLastByMaccAsync()` | `Utils.redisOdlLastByMac:{idxMacc}` |
|
||||||
|
| 7 | `ListValuesFilt` | `IocDbController.ListValuesFiltAsync()` | `Utils.redisConfFlux:{tag}` |
|
||||||
|
| 8 | `Macchine2SlaveGetAllAsync` | `IocDbController.Macchine2SlaveAsync()` | `Utils.redisBaseAddr:M2STab` |
|
||||||
|
| 9 | `MacchineGetFilt` | `_productionRepository.MacchineGetFiltAsync()` | `Utils.redisMacList:{keyGrp}` |
|
||||||
|
| 10 | `MacchineRecipeArchive` | `_productionRepository.MacchineGetFiltAsync("*")` → LINQ | `Utils.redisMacRecipePath:{idxMacc}` |
|
||||||
|
| 11 | `MseGetAllAsync` | `IocDbController.MseGetAllAsync(maxAge)` | `Constants.redisMseKey` (+ forceDb) |
|
||||||
|
| 12 | `OdlCurrByMaccAsync` | `IocDbController.OdlCurrByMaccAsync()` | `Utils.redisOdlList:Current:{idxMacc}` |
|
||||||
|
| 13 | `POdlGetByKey` | `_productionRepository.PODL_getByKeyAsync()` | `Utils.redisPOdlByPOdl:{idxPODL}` |
|
||||||
|
| 14 | `POdlGetByMaccArtAsync` | `IocDbController.POdlGetByMaccArtAsync()` | `Utils.redisPOdlByMaccArt:{idxMacc}...` |
|
||||||
|
| 15 | `ConfFluxMach` | `IocDbController.ConfFluxFiltAsync()` → LINQ | `Utils.redisConfFlux:{tag}` |
|
||||||
|
| 16 | `FluxLogFirstByMachAsync` | `IocDbController.FluxLogFirstByMaccAsync()` → LINQ | `Utils.redisFluxLogFirstByMac:{key}` |
|
||||||
|
| 17 | `FluxLogGetLastByMachAsync` | `IocDbController.FluxLogGetLastFiltAsync()` → LINQ | `Utils.redisFluxLogByMac:{key}` |
|
||||||
|
|
||||||
|
### ❌ NON MIGRATI (Scrittura / TTL / Hash-only — 30+ metodi)
|
||||||
|
|
||||||
|
Questi metodi usano Redis ma **NON** hanno pattern cache-aside (StringGet → DB → StringSet). Sono dati transituali IOB o write-through:
|
||||||
|
|
||||||
|
| Categoria | Metodi | Motivazione |
|
||||||
|
|-----------|--------|-------------|
|
||||||
|
| **Scrittura Only (StringSet)** | `MachineParamListSetAsync`, `SaveMachine2Iob`, `SaveMachineIobConf`, `SetIobConfYamlAsync`, `SetIobMemMap`, `UpsertCurrObjItemsAsync` | Solo StringSet, zero StringGet |
|
||||||
|
| **Lock/TTL-based** | `AutoStartOdlAsync` (veto), `ScriviKeepAliveAsync` (TTL 30s) | Pattern di lock, non di cache |
|
||||||
|
| **Hash-based IOB State** | `MachineParamListAsync`, `AddCheckTask4Machine`, `AddOptPar4Machine`, `AddTask4Machine`, `AddTask4MacListAsync`, `mOptParMacchina`, `mSavedTaskMacchina`, `mTaskMacchina`, `mTaskMacchinaAsync`, `mDatiMacchineAsync`, `mTabMSMIAsync`, `StateMachInByKeyAsync`, `ValoreSmiAsync`, `StateMachInByKeyAsync` | Redis Hash per dati in tempo reale IOB (transazionali), non Database-backed |
|
||||||
|
| **Hash Reset Helpers** | `ResetDatiMacchinaAsync`, `resetMSMIAsync`, `resetSMIAsync` | Reset di tabelle Hash Redis, non cache |
|
||||||
|
| **Redis GetHash Helpers** | `RedisGetHash`, `RedisGetHashAsync`, `RedisGetHashDict`, `RedisGetHashDictAsync`, `RedisSetHash`, `RedisSetHashAsync`, `RedisSetHashDict`, `RedisSetHashDictAsync`, `RedisCountKey`, `RedisDelKey`, `RedisKeyPresent`, `RedisGetHashField` | Helper utility Redis, non metodi di business |
|
||||||
|
|
||||||
|
### ⚠️ DA VERIFICARE (Pattern atipico - 4 metodi)
|
||||||
|
|
||||||
|
Questi metodi hanno Redis ma il pattern non è lo standard cache-aside. Vanno analizzati caso per caso:
|
||||||
|
|
||||||
|
| # | Metodo | Riga | Motivo Verifica |
|
||||||
|
|---|--------|------|-----------------|
|
||||||
|
| 1 | `GetCurrOdlAsync` | ~892 | Chiama `GetCurrOdlByProdAsync()` (metodo interno complesso), non `IocDbController.XXX()` direttamente. Pattern: StringGet → DB → StringSet. Verificare se `GetCurrOdlByProdAsync` è una stored procedure. |
|
||||||
|
| 2 | `StatoProdMacchinaAsync` (private) | ~3267 | Ha parametro `forceDb`, cache breve (60s pattern). Pattern valido ma private. |
|
||||||
|
| 3 | `verificaIdxMacchinaAsync` | ~3267 | Verifica esistenza macchina, non un cache-aside standard. |
|
||||||
|
| 4 | `ListMasterAsync` / `ListSlaveAsync` | ~2820/~2840 | Cache-aside valido ma derivano da `Macchine2SlaveGetAllAsync()` (già migrata). Potrebbero essere rimossi in favore di un unico repository. |
|
||||||
|
|
||||||
|
## Priorità Operativa
|
||||||
|
|
||||||
|
1. ~~**F1 immediata**~~ — ✅ Completata
|
||||||
|
2. ~~**F2 FusionCache**~~ — ✅ Completata (18 metodi migrati)
|
||||||
|
3. **F3 Repository IoC** — Prossimo step maggiore: decomporre `MpIocController` (1480 righe, 82 metodi) in 7-10 repository specialistici
|
||||||
|
4. **F4 Scomposizione MpDataService** — Quando Fase 3 è stabile, dividere il monolite da 3516 righe
|
||||||
|
5. **Verifica metodi atipici** — I 4 metodi con pattern non-standards vanno valutati manualmente
|
||||||
|
|
||||||
|
## Note
|
||||||
|
|
||||||
|
- MpIocController usa già `IDbContextFactory` correttamente — il problema è che è un Singleton usato da un altro Singleton (MpDataService)
|
||||||
|
- `IIocRepository` (già esistente) ha solo 16 metodi ed è mai usato da MpDataService
|
||||||
|
- I repository SPEC (Anag, Dossier, FluxLog, Production) sono già usati da alcuni metodi — sfruttarli dove possibile
|
||||||
|
- La struttura `MP.Data/Controllers/` è ingannevole: `MpIocController` è un servizio, non un controller Web API
|
||||||
|
- `redisConnAdmin` (connessione Redis admin) sembra non essere mai usata — verificare eliminazione
|
||||||
|
- **Build finale:** ✅ 0 errori, 12 warnings (tutti nullable reference preesistenti)
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RootNamespace>MP.Land</RootNamespace>
|
<RootNamespace>MP.Land</RootNamespace>
|
||||||
<Version>8.16.2606.0408</Version>
|
<Version>8.16.2606.1117</Version>
|
||||||
<Configurations>Debug;Release;Debug_LiManDebug</Configurations>
|
<Configurations>Debug;Release;Debug_LiManDebug</Configurations>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
<RunAnalyzersDuringBuild>True</RunAnalyzersDuringBuild>
|
<RunAnalyzersDuringBuild>True</RunAnalyzersDuringBuild>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<i>Modulo Tablet MAPO - DotNet6</i>
|
<i>Modulo Tablet MAPO - DotNet6</i>
|
||||||
<h4>Versione: 8.16.2606.0408</h4>
|
<h4>Versione: 8.16.2606.1117</h4>
|
||||||
<br />
|
<br />
|
||||||
Note di rilascio:
|
Note di rilascio:
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
8.16.2606.0408
|
8.16.2606.1117
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<item>
|
<item>
|
||||||
<version>8.16.2606.0408</version>
|
<version>8.16.2606.1117</version>
|
||||||
<url>https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/MP.Land.zip</url>
|
<url>https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/MP.Land.zip</url>
|
||||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/ChangeLog.html</changelog>
|
<changelog>https://nexus.steamware.net/repository/SWS/MP-LAND/stable/LAST/ChangeLog.html</changelog>
|
||||||
<mandatory>false</mandatory>
|
<mandatory>false</mandatory>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<RootNamespace>MP.MON</RootNamespace>
|
<RootNamespace>MP.MON</RootNamespace>
|
||||||
<AssemblyName>$(AssemblyName.Replace(' ', '_'))</AssemblyName>
|
<AssemblyName>$(AssemblyName.Replace(' ', '_'))</AssemblyName>
|
||||||
<Version>8.16.2606.408</Version>
|
<Version>8.16.2606.1117</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<i>Modulo MAPOSPEC </i>
|
<i>Modulo MAPOSPEC </i>
|
||||||
<h4>Versione: 8.16.2606.408</h4>
|
<h4>Versione: 8.16.2606.1117</h4>
|
||||||
<br /> Note di rilascio:
|
<br /> Note di rilascio:
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
8.16.2606.408
|
8.16.2606.1117
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<item>
|
<item>
|
||||||
<version>8.16.2606.408</version>
|
<version>8.16.2606.1117</version>
|
||||||
<url>https://nexus.steamware.net/repository/SWS/MP-MON/stable/LAST/MP.MON.zip</url>
|
<url>https://nexus.steamware.net/repository/SWS/MP-MON/stable/LAST/MP.MON.zip</url>
|
||||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-MON/stable/LAST/ChangeLog.html</changelog>
|
<changelog>https://nexus.steamware.net/repository/SWS/MP-MON/stable/LAST/ChangeLog.html</changelog>
|
||||||
<mandatory>false</mandatory>
|
<mandatory>false</mandatory>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RootNamespace>MP.Prog</RootNamespace>
|
<RootNamespace>MP.Prog</RootNamespace>
|
||||||
<Version>8.16.2606.0408</Version>
|
<Version>8.16.2606.1117</Version>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<i>Modulo gestione Programmi MAPO</i>
|
<i>Modulo gestione Programmi MAPO</i>
|
||||||
<h4>Versione: 8.16.2606.0408</h4>
|
<h4>Versione: 8.16.2606.1117</h4>
|
||||||
<br />
|
<br />
|
||||||
Note di rilascio:
|
Note di rilascio:
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
8.16.2606.0408
|
8.16.2606.1117
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<item>
|
<item>
|
||||||
<version>8.16.2606.0408</version>
|
<version>8.16.2606.1117</version>
|
||||||
<url>https://nexus.steamware.net/repository/SWS/MP-PROG/stable/LAST/MP.Prog.zip</url>
|
<url>https://nexus.steamware.net/repository/SWS/MP-PROG/stable/LAST/MP.Prog.zip</url>
|
||||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-PROG/stable/LAST/ChangeLog.html</changelog>
|
<changelog>https://nexus.steamware.net/repository/SWS/MP-PROG/stable/LAST/ChangeLog.html</changelog>
|
||||||
<mandatory>false</mandatory>
|
<mandatory>false</mandatory>
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<RootNamespace>MP.RIOC</RootNamespace>
|
<RootNamespace>MP.RIOC</RootNamespace>
|
||||||
<Version>8.16.2606.408</Version>
|
<Version>8.16.2606.1218</Version>
|
||||||
|
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
+35
-3
@@ -10,14 +10,30 @@ using System.Diagnostics;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
|
|
||||||
|
// Forza il ThreadPool a tenere pronti almeno 500 thread per i calcoli e 500 per l'I/O di rete
|
||||||
|
ThreadPool.SetMinThreads(500, 500);
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// recupero env corrente
|
// RECUPERO L'AMBIENTE REALE (Che ora IIS passa correttamente come 'Staging')
|
||||||
var env = builder.Environment;
|
var env = builder.Environment;
|
||||||
|
|
||||||
|
// FORZA IL CARICAMENTO CORRETTO DEI JSON CON LA GERARCHIA DI AMBIENTE
|
||||||
|
builder.Configuration
|
||||||
|
.SetBasePath(env.ContentRootPath)
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
// recupero env corrente
|
||||||
var logger = LogManager.Setup()
|
var logger = LogManager.Setup()
|
||||||
.LoadConfigurationFromAppSettings()
|
.LoadConfigurationFromAppSettings()
|
||||||
.GetCurrentClassLogger();
|
.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
builder.Logging.ClearProviders();
|
||||||
|
builder.Host.UseNLog();
|
||||||
|
|
||||||
var assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString();
|
var assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString();
|
||||||
logger.Info($"MP.RIOC | Program.cs: startup | v.{assemblyVersion}");
|
logger.Info($"MP.RIOC | Program.cs: startup | v.{assemblyVersion}");
|
||||||
logger.Info($"Current ASPNETCORE_ENVIRONMENT: {env.EnvironmentName}");
|
logger.Info($"Current ASPNETCORE_ENVIRONMENT: {env.EnvironmentName}");
|
||||||
@@ -57,23 +73,35 @@ builder.Services.AddDbContextFactory<MoonPro_UtilsContext>(options =>
|
|||||||
builder.Services.AddIocDataLayer();
|
builder.Services.AddIocDataLayer();
|
||||||
|
|
||||||
// 1. Configurazione dell'invoker personalizzato (Risolve i tuoi errori)
|
// 1. Configurazione dell'invoker personalizzato (Risolve i tuoi errori)
|
||||||
|
// 1. Configurazione dell'invoker personalizzato (Potenziato con il Pooling)
|
||||||
var httpClientInvoker = new HttpMessageInvoker(new SocketsHttpHandler
|
var httpClientInvoker = new HttpMessageInvoker(new SocketsHttpHandler
|
||||||
{
|
{
|
||||||
UseProxy = false,
|
UseProxy = false,
|
||||||
AllowAutoRedirect = false,
|
AllowAutoRedirect = false,
|
||||||
AutomaticDecompression = DecompressionMethods.None,
|
AutomaticDecompression = DecompressionMethods.None,
|
||||||
UseCookies = false,
|
UseCookies = false,
|
||||||
// Correzione per il tracing: usa il propagatore corrente di sistema
|
|
||||||
ActivityHeadersPropagator = DistributedContextPropagator.Current,
|
ActivityHeadersPropagator = DistributedContextPropagator.Current,
|
||||||
ConnectTimeout = TimeSpan.FromSeconds(60),
|
ConnectTimeout = TimeSpan.FromSeconds(60),
|
||||||
|
|
||||||
// Gestione certificato (ignora errori per localhost/test)
|
// ==================================================================
|
||||||
|
// 🚀 LE TRE RIGHE PER ABBATTERE IL MURO DEI 2 SECONDI SOTTO STRESS
|
||||||
|
// ==================================================================
|
||||||
|
// Permette a YARP di aprire fino a 5000 canali paralleli contemporanei verso IIS
|
||||||
|
MaxConnectionsPerServer = 5000,
|
||||||
|
|
||||||
|
// Tiene caldi i socket ed evita di rifare l'handshake TCP/TLS a ogni richiesta
|
||||||
|
PooledConnectionLifetime = TimeSpan.FromMinutes(15),
|
||||||
|
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2),
|
||||||
|
// ==================================================================
|
||||||
|
|
||||||
|
// Gestione certificato (Invariata)
|
||||||
SslOptions = new System.Net.Security.SslClientAuthenticationOptions
|
SslOptions = new System.Net.Security.SslClientAuthenticationOptions
|
||||||
{
|
{
|
||||||
RemoteCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
|
RemoteCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Registrazione nella Dependency Injection (Invariata)
|
||||||
builder.Services.AddSingleton(httpClientInvoker);
|
builder.Services.AddSingleton(httpClientInvoker);
|
||||||
builder.Services.AddHttpForwarder();
|
builder.Services.AddHttpForwarder();
|
||||||
|
|
||||||
@@ -161,6 +189,10 @@ app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments(routePath, StringComparis
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// test per ambiente di esecuzione InProcess...
|
||||||
|
app.MapGet("api/alive", () =>
|
||||||
|
$"OK - Girando in: {System.Diagnostics.Process.GetCurrentProcess().ProcessName}");
|
||||||
|
|
||||||
// 6. Definizione degli Endpoints locali
|
// 6. Definizione degli Endpoints locali
|
||||||
app.MapRazorPages();
|
app.MapRazorPages();
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
|
<AllowUntrustedCertificate>True</AllowUntrustedCertificate>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<MsDeploySkipRules Include="SkipLogFiles">
|
<MsDeploySkipRules Include="SkipLogFiles">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<i>Modulo MP-RIOC </i>
|
<i>Modulo MP-RIOC </i>
|
||||||
<h4>Versione: 8.16.2606.408</h4>
|
<h4>Versione: 8.16.2606.1218</h4>
|
||||||
<br /> Note di rilascio:
|
<br /> Note di rilascio:
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
8.16.2606.408
|
8.16.2606.1218
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<item>
|
<item>
|
||||||
<version>8.16.2606.408</version>
|
<version>8.16.2606.1218</version>
|
||||||
<url>https://nexus.steamware.net/repository/SWS/MP-RIOC/stable/LAST/MP.RIOC.zip</url>
|
<url>https://nexus.steamware.net/repository/SWS/MP-RIOC/stable/LAST/MP.RIOC.zip</url>
|
||||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-RIOC/stable/LAST/ChangeLog.html</changelog>
|
<changelog>https://nexus.steamware.net/repository/SWS/MP-RIOC/stable/LAST/ChangeLog.html</changelog>
|
||||||
<mandatory>false</mandatory>
|
<mandatory>false</mandatory>
|
||||||
|
|||||||
@@ -128,10 +128,15 @@ namespace MP.RIOC.Services
|
|||||||
SentinelValue
|
SentinelValue
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// 1b. Imposta TTL 30 giorni su bucket hourly per prevenire chiavi orfane
|
||||||
|
tasks.Add(batch.KeyExpireAsync(hourKey, TimeSpan.FromDays(30)));
|
||||||
|
|
||||||
// 2. INVIO DISTRIBUZIONE STATUS CODES
|
// 2. INVIO DISTRIBUZIONE STATUS CODES
|
||||||
if (stat.StatusCodes.Any())
|
if (stat.StatusCodes.Any())
|
||||||
{
|
{
|
||||||
var statusKey = hourKey + ":status";
|
var statusKey = hourKey + ":status";
|
||||||
|
// Imposta TTL 30 giorni su chiavi ausiliarie per prevenire chiavi orfane
|
||||||
|
tasks.Add(batch.KeyExpireAsync(statusKey, TimeSpan.FromDays(30)));
|
||||||
foreach (var status in stat.StatusCodes)
|
foreach (var status in stat.StatusCodes)
|
||||||
{
|
{
|
||||||
tasks.Add(batch.HashIncrementAsync(statusKey, status.Key.ToString(), status.Value));
|
tasks.Add(batch.HashIncrementAsync(statusKey, status.Key.ToString(), status.Value));
|
||||||
@@ -144,6 +149,8 @@ namespace MP.RIOC.Services
|
|||||||
if (stat.ErrorMessages.Any())
|
if (stat.ErrorMessages.Any())
|
||||||
{
|
{
|
||||||
var errorKey = hourKey + ":errors";
|
var errorKey = hourKey + ":errors";
|
||||||
|
// Imposta TTL 30 giorni su chiavi ausiliarie per prevenire chiavi orfane
|
||||||
|
tasks.Add(batch.KeyExpireAsync(errorKey, TimeSpan.FromDays(30)));
|
||||||
foreach (var error in stat.ErrorMessages)
|
foreach (var error in stat.ErrorMessages)
|
||||||
{
|
{
|
||||||
// Usiamo HashIncrement per aggregare messaggi uguali
|
// Usiamo HashIncrement per aggregare messaggi uguali
|
||||||
@@ -159,6 +166,9 @@ namespace MP.RIOC.Services
|
|||||||
var daysIndex = DaysIndexKey(dest, machineId);
|
var daysIndex = DaysIndexKey(dest, machineId);
|
||||||
var dayScore = ToEpochSeconds(dayStart);
|
var dayScore = ToEpochSeconds(dayStart);
|
||||||
|
|
||||||
|
// 5. Imposta TTL 30 giorni anche sulle chiavi index per pulizia automatica
|
||||||
|
tasks.Add(batch.KeyExpireAsync(hoursIndex, TimeSpan.FromDays(30)));
|
||||||
|
|
||||||
if (!dailyAggregates.TryGetValue(dayKey, out var agg))
|
if (!dailyAggregates.TryGetValue(dayKey, out var agg))
|
||||||
{
|
{
|
||||||
agg = new AggregatedStats();
|
agg = new AggregatedStats();
|
||||||
@@ -174,6 +184,9 @@ namespace MP.RIOC.Services
|
|||||||
|
|
||||||
// Aggiungiamo l'indice al batch
|
// Aggiungiamo l'indice al batch
|
||||||
tasks.Add(batch.SortedSetAddAsync(daysIndex, dayKey, dayScore));
|
tasks.Add(batch.SortedSetAddAsync(daysIndex, dayKey, dayScore));
|
||||||
|
|
||||||
|
// 5. Imposta TTL 30 giorni su chiave daily per prevenire chiavi orfane
|
||||||
|
tasks.Add(batch.KeyExpireAsync(dayKey, TimeSpan.FromDays(30)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- INVIO AGGREGATI DAILY A REDIS ---
|
// --- INVIO AGGREGATI DAILY A REDIS ---
|
||||||
@@ -196,6 +209,9 @@ namespace MP.RIOC.Services
|
|||||||
agg.NoReply.ToString(CultureInfo.InvariantCulture),
|
agg.NoReply.ToString(CultureInfo.InvariantCulture),
|
||||||
SentinelValue
|
SentinelValue
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Imposta TTL 30 giorni su bucket daily aggregato
|
||||||
|
tasks.Add(batch.KeyExpireAsync(key, TimeSpan.FromDays(30)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Esegui tutto il batch in un unico round-trip
|
// Esegui tutto il batch in un unico round-trip
|
||||||
|
|||||||
@@ -33,8 +33,23 @@ namespace MP.RIOC.Services
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//await ProcessDayLiveMetricsAsync();
|
||||||
|
//await ProcessHourLiveMetricsAsync();
|
||||||
|
|
||||||
|
// 2. 🚀 COSTRINGIAMO IL FLUSH A GIRARE IN BACKGROUND
|
||||||
|
// Task.Run prende l'intera esecuzione e la sposta su un thread separato.
|
||||||
|
// In questo modo, anche se l'Upsert fa calcoli pesanti o blocca momentaneamente,
|
||||||
|
// i thread principali di YARP rimangono liberi al 100% di rispondere a wrk in 2ms.
|
||||||
|
await Task.Run(async () =>
|
||||||
|
{
|
||||||
|
// Cede immediatamente il controllo per evitare di monopolizzare il thread corrente
|
||||||
|
await Task.Yield();
|
||||||
|
|
||||||
|
// Esegue i tuoi due metodi (che manterranno i loro scope interni asincroni)
|
||||||
await ProcessDayLiveMetricsAsync();
|
await ProcessDayLiveMetricsAsync();
|
||||||
await ProcessHourLiveMetricsAsync();
|
await ProcessHourLiveMetricsAsync();
|
||||||
|
}, stoppingToken);
|
||||||
|
// poi attendo...
|
||||||
await Task.Delay(TimeSpan.FromSeconds(interval), stoppingToken);
|
await Task.Delay(TimeSpan.FromSeconds(interval), stoppingToken);
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException) { break; }
|
catch (TaskCanceledException) { break; }
|
||||||
@@ -66,6 +81,68 @@ namespace MP.RIOC.Services
|
|||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancellazione ricorsiva chiavi ausiliarie (:status, :errors) e rimozione dall'indice
|
||||||
|
/// </summary>
|
||||||
|
private async Task DeleteAuxKeysAndIndexAsync(RedisKey sKey, RedisKey indexKey, IBatch batch, List<Task> pendingOps)
|
||||||
|
{
|
||||||
|
string sKeyStr = sKey.ToString();
|
||||||
|
string keyDir = sKeyStr.Substring(0, sKeyStr.LastIndexOf(':'));
|
||||||
|
|
||||||
|
// Cancella :status dal sorted set e dalla hash
|
||||||
|
string statusKey = keyDir + ":status";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pendingOps.Add(batch.SortedSetRemoveAsync(indexKey, statusKey));
|
||||||
|
pendingOps.Add(batch.KeyDeleteAsync(statusKey));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
// Cancella :errors dal sorted set e dalla hash
|
||||||
|
string errorKey = keyDir + ":errors";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pendingOps.Add(batch.SortedSetRemoveAsync(indexKey, errorKey));
|
||||||
|
pendingOps.Add(batch.KeyDeleteAsync(errorKey));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
// Cancella chiave ausiliaria :status anche da un eventuale indice days se presente
|
||||||
|
if (statusKey.Contains(":stats:hours:"))
|
||||||
|
{
|
||||||
|
string daysIndex = statusKey.Replace(":stats:hours:", ":stats:days:");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pendingOps.Add(batch.SortedSetRemoveAsync(daysIndex, statusKey));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancella chiave ausiliaria :errors anche da un eventuale indice days se presente
|
||||||
|
if (errorKey.Contains(":stats:hours:"))
|
||||||
|
{
|
||||||
|
string daysIndex = errorKey.Replace(":stats:hours:", ":stats:days:");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pendingOps.Add(batch.SortedSetRemoveAsync(daysIndex, errorKey));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if false
|
||||||
|
/// <summary>
|
||||||
|
/// Recupera il TTL residuo di una chiave Redis (-1 = nessun TTL, -2 = chiave non esiste)
|
||||||
|
/// </summary>
|
||||||
|
private TimeSpan? GetKeyTtl(RedisKey key)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _db.KeyTimeToLive(key);
|
||||||
|
}
|
||||||
|
catch { return null; }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processing dati giornalieri (da Redis a DB)
|
/// Processing dati giornalieri (da Redis a DB)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -97,6 +174,7 @@ namespace MP.RIOC.Services
|
|||||||
};
|
};
|
||||||
|
|
||||||
var batch = _db.CreateBatch();
|
var batch = _db.CreateBatch();
|
||||||
|
var pendingOps = new List<Task>();
|
||||||
foreach (var pattern in patternsToScan)
|
foreach (var pattern in patternsToScan)
|
||||||
{
|
{
|
||||||
// Nota: KeyScanAsync/KeysAsync e' disponibile su IServer
|
// Nota: KeyScanAsync/KeysAsync e' disponibile su IServer
|
||||||
@@ -110,21 +188,36 @@ namespace MP.RIOC.Services
|
|||||||
foreach (var statKey in memberKeys)
|
foreach (var statKey in memberKeys)
|
||||||
{
|
{
|
||||||
var sKey = (RedisKey)$"{statKey}";
|
var sKey = (RedisKey)$"{statKey}";
|
||||||
#if false
|
|
||||||
if (!TryParseKeyMetadata(sKey, out string dest, out string method, out string machId, out DateTime timestamp, out bool isHourType))
|
|
||||||
continue;
|
|
||||||
#endif
|
|
||||||
if (!TryParseKeyMetadata(sKey, out var meta) || meta.IsHourType) continue;
|
if (!TryParseKeyMetadata(sKey, out var meta) || meta.IsHourType) continue;
|
||||||
|
|
||||||
// Se fosse scaduta e abbiamo il permesso, segnamola per la cancellazione
|
// Verifica se la chiave è "orfana"
|
||||||
if (meta.Timestamp < currentDayStart && deleteConfirmed)
|
bool isOrphanKey = meta.Timestamp < currentDayStart;
|
||||||
|
#if false
|
||||||
|
bool isOrphanKey = false;
|
||||||
|
var keyTtl = GetKeyTtl(sKey);
|
||||||
|
if (keyTtl == null)
|
||||||
|
{
|
||||||
|
isOrphanKey = meta.Timestamp < currentDayStart;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isOrphanKey = keyTtl.Value.TotalSeconds < 0 || keyTtl.Value.TotalDays < 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Se è orfana e abbiamo il permesso, segnamola per la cancellazione
|
||||||
|
// NOTA: non usiamo il confronto con currentDayStart perché taglierebbe fuori
|
||||||
|
// i dati delle ore/giorni precedenti che devono essere ancora processati dal DB
|
||||||
|
if (isOrphanKey && deleteConfirmed)
|
||||||
{
|
{
|
||||||
// 1. Segna la chiave Hash (Dati) per l'eliminazione
|
// 1. Segna la chiave Hash (Dati) per l'eliminazione
|
||||||
keysToDelete.Add(sKey);
|
keysToDelete.Add(sKey);
|
||||||
|
|
||||||
// 2. CORREZIONE: Devi rimuovere il riferimento dal Sorted Set (Indice)
|
// 2. Rimuovi il riferimento dal Sorted Set (Indice)
|
||||||
// Usiamo il batch per essere efficienti
|
pendingOps.Add(batch.SortedSetRemoveAsync(indexKey, statKey));
|
||||||
_ = batch.SortedSetRemoveAsync(indexKey, statKey);
|
|
||||||
|
// 3. Cancellazione ricorsiva delle chiavi ausiliarie (:status, :errors, :days)
|
||||||
|
await DeleteAuxKeysAndIndexAsync(sKey, indexKey, batch, pendingOps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recupero dati dalla Hash
|
// Recupero dati dalla Hash
|
||||||
@@ -137,7 +230,6 @@ namespace MP.RIOC.Services
|
|||||||
dict.TryGetValue("totalMs", out var totalMsStr))
|
dict.TryGetValue("totalMs", out var totalMsStr))
|
||||||
{
|
{
|
||||||
long count = long.Parse(countStr);
|
long count = long.Parse(countStr);
|
||||||
count = long.Parse(countStr);
|
|
||||||
double totalMs = double.Parse(totalMsStr, CultureInfo.InvariantCulture);
|
double totalMs = double.Parse(totalMsStr, CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
double maxMs = dict.ContainsKey("maxMs") ? double.Parse(dict["maxMs"], CultureInfo.InvariantCulture) : 0;
|
double maxMs = dict.ContainsKey("maxMs") ? double.Parse(dict["maxMs"], CultureInfo.InvariantCulture) : 0;
|
||||||
@@ -172,6 +264,8 @@ namespace MP.RIOC.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch.Execute();
|
batch.Execute();
|
||||||
|
// attendo conclusione
|
||||||
|
await Task.WhenAll(pendingOps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- FASE UPSERT DB ---
|
// --- FASE UPSERT DB ---
|
||||||
@@ -187,13 +281,16 @@ namespace MP.RIOC.Services
|
|||||||
if (deleteConfirmed && keysToDelete.Any())
|
if (deleteConfirmed && keysToDelete.Any())
|
||||||
{
|
{
|
||||||
var batch = _db.CreateBatch();
|
var batch = _db.CreateBatch();
|
||||||
|
var pendingOps = new List<Task>();
|
||||||
int deletedCount = 0;
|
int deletedCount = 0;
|
||||||
foreach (var key in keysToDelete)
|
foreach (var key in keysToDelete)
|
||||||
{
|
{
|
||||||
_ = batch.KeyDeleteAsync(key);
|
pendingOps.Add(batch.KeyDeleteAsync(key));
|
||||||
deletedCount++;
|
deletedCount++;
|
||||||
}
|
}
|
||||||
batch.Execute();
|
batch.Execute();
|
||||||
|
// attendo conclusione
|
||||||
|
await Task.WhenAll(pendingOps);
|
||||||
Log.Info($"[CLEANUP DAY] Deleted {deletedCount} expired metric keys from Redis");
|
Log.Info($"[CLEANUP DAY] Deleted {deletedCount} expired metric keys from Redis");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,6 +327,7 @@ namespace MP.RIOC.Services
|
|||||||
};
|
};
|
||||||
|
|
||||||
var batch = _db.CreateBatch();
|
var batch = _db.CreateBatch();
|
||||||
|
var pendingOps = new List<Task>();
|
||||||
foreach (var pattern in patternsToScan)
|
foreach (var pattern in patternsToScan)
|
||||||
{
|
{
|
||||||
// Nota: KeyScanAsync/KeysAsync e' disponibile su IServer
|
// Nota: KeyScanAsync/KeysAsync e' disponibile su IServer
|
||||||
@@ -244,26 +342,37 @@ namespace MP.RIOC.Services
|
|||||||
{
|
{
|
||||||
var sKey = (RedisKey)$"{statKey}";
|
var sKey = (RedisKey)$"{statKey}";
|
||||||
if (!TryParseKeyMetadata(sKey, out var meta) || !meta.IsHourType) continue;
|
if (!TryParseKeyMetadata(sKey, out var meta) || !meta.IsHourType) continue;
|
||||||
#if false
|
|
||||||
if (!TryParseKeyMetadata(sKey, out string dest, out string method, out string machId, out DateTime timestamp, out bool isHourType))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Verifica se la chiave fosse scaduta rispetto all'orario corrente
|
// Verifica se la chiave è "orfana"
|
||||||
bool isExpired = isHourType
|
bool isOrphanKey = meta.Timestamp < currentHourStart;
|
||||||
? timestamp < currentHourStart
|
#if false
|
||||||
: false;
|
bool isOrphanKey = false;
|
||||||
//: timestamp < currentDayStart;
|
var keyTtl = GetKeyTtl(sKey);
|
||||||
|
if (keyTtl == null)
|
||||||
|
{
|
||||||
|
// Nessun TTL recuperato = chiave senza scadenza = orfana se > 7 gg
|
||||||
|
DateTime cutoffHour = DateTime.Now.AddDays(-7);
|
||||||
|
isOrphanKey = meta.Timestamp < cutoffHour;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isOrphanKey = keyTtl.Value.TotalSeconds < 0 || keyTtl.Value.TotalDays < 15;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Se fosse scaduta e abbiamo il permesso, segnamola per la cancellazione
|
// Se è orfana e abbiamo il permesso, segnamola per la cancellazione
|
||||||
if (meta.Timestamp < currentHourStart && deleteConfirmed)
|
// NOTA: non usiamo il confronto con currentHourStart perché taglierebbe fuori
|
||||||
|
// i dati delle ore precedenti che devono essere ancora processati dal DB
|
||||||
|
if (isOrphanKey && deleteConfirmed)
|
||||||
{
|
{
|
||||||
// 1. Segna la chiave Hash (Dati) per l'eliminazione
|
// 1. Segna la chiave Hash (Dati) per l'eliminazione
|
||||||
keysToDelete.Add(sKey);
|
keysToDelete.Add(sKey);
|
||||||
|
|
||||||
// 2. CORREZIONE: Devi rimuovere il riferimento dal Sorted Set (Indice)
|
// 2. Rimuovi il riferimento dal Sorted Set (Indice)
|
||||||
// Usiamo il batch per essere efficienti
|
pendingOps.Add(batch.SortedSetRemoveAsync(indexKey, statKey));
|
||||||
_ = batch.SortedSetRemoveAsync(indexKey, statKey);
|
|
||||||
|
// 3. Cancellazione ricorsiva chiavi ausiliarie
|
||||||
|
await DeleteAuxKeysAndIndexAsync(sKey, indexKey, batch, pendingOps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recupero dati dalla Hash
|
// Recupero dati dalla Hash
|
||||||
@@ -276,7 +385,6 @@ namespace MP.RIOC.Services
|
|||||||
dict.TryGetValue("totalMs", out var totalMsStr))
|
dict.TryGetValue("totalMs", out var totalMsStr))
|
||||||
{
|
{
|
||||||
long count = long.Parse(countStr);
|
long count = long.Parse(countStr);
|
||||||
count = long.Parse(countStr);
|
|
||||||
double totalMs = double.Parse(totalMsStr, CultureInfo.InvariantCulture);
|
double totalMs = double.Parse(totalMsStr, CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
double maxMs = dict.ContainsKey("maxMs") ? double.Parse(dict["maxMs"], CultureInfo.InvariantCulture) : 0;
|
double maxMs = dict.ContainsKey("maxMs") ? double.Parse(dict["maxMs"], CultureInfo.InvariantCulture) : 0;
|
||||||
@@ -310,6 +418,8 @@ namespace MP.RIOC.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch.Execute();
|
batch.Execute();
|
||||||
|
// attendo conclusione
|
||||||
|
await Task.WhenAll(pendingOps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- FASE UPSERT DB ---
|
// --- FASE UPSERT DB ---
|
||||||
@@ -325,16 +435,20 @@ namespace MP.RIOC.Services
|
|||||||
if (deleteConfirmed && keysToDelete.Count > 0)
|
if (deleteConfirmed && keysToDelete.Count > 0)
|
||||||
{
|
{
|
||||||
var batch = _db.CreateBatch();
|
var batch = _db.CreateBatch();
|
||||||
|
var pendingOps = new List<Task>();
|
||||||
int deletedCount = 0;
|
int deletedCount = 0;
|
||||||
foreach (var key in keysToDelete)
|
foreach (var key in keysToDelete)
|
||||||
{
|
{
|
||||||
_ = batch.KeyDeleteAsync(key);
|
pendingOps.Add(batch.KeyDeleteAsync(key));
|
||||||
deletedCount++;
|
deletedCount++;
|
||||||
}
|
}
|
||||||
batch.Execute();
|
batch.Execute();
|
||||||
|
// attendo conclusione
|
||||||
|
await Task.WhenAll(pendingOps);
|
||||||
Log.Info($"[CLEANUP HOUR] Deleted {deletedCount} expired metric keys from Redis");
|
Log.Info($"[CLEANUP HOUR] Deleted {deletedCount} expired metric keys from Redis");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryParseKeyMetadata(RedisKey key, out KeyMeta meta)
|
private bool TryParseKeyMetadata(RedisKey key, out KeyMeta meta)
|
||||||
{
|
{
|
||||||
meta = new KeyMeta();
|
meta = new KeyMeta();
|
||||||
@@ -345,7 +459,7 @@ namespace MP.RIOC.Services
|
|||||||
var p = relativeKey.Split(':');
|
var p = relativeKey.Split(':');
|
||||||
if (p.Length < 4) return false;
|
if (p.Length < 4) return false;
|
||||||
|
|
||||||
meta.IsHourType = p[1].Equals("hour", StringComparison.InvariantCultureIgnoreCase);
|
meta.IsHourType = p[1].Contains("hour", StringComparison.InvariantCultureIgnoreCase);
|
||||||
meta.Dest = p[2];
|
meta.Dest = p[2];
|
||||||
if (meta.IsHourType)
|
if (meta.IsHourType)
|
||||||
{
|
{
|
||||||
@@ -363,60 +477,7 @@ namespace MP.RIOC.Services
|
|||||||
catch { return false; }
|
catch { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#if false
|
#endregion Private Methods
|
||||||
private bool TryParseKeyMetadata(RedisKey key, out string dest, out string method, out string machId, out DateTime timestamp, out bool isHourType)
|
|
||||||
{
|
|
||||||
dest = "NA";
|
|
||||||
method = "NA";
|
|
||||||
machId = "ALL";
|
|
||||||
timestamp = DateTime.MinValue;
|
|
||||||
isHourType = true;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string k = key.ToString();
|
|
||||||
string relativeKey = k.Replace($"{_redisBaseKey}:", "");
|
|
||||||
var parts = relativeKey.Split(':');
|
|
||||||
|
|
||||||
if (parts.Length < 4) return false;
|
|
||||||
|
|
||||||
string type = parts[1]; // "hour" o "day"
|
|
||||||
dest = parts[2];
|
|
||||||
|
|
||||||
if (type == "hour")
|
|
||||||
{
|
|
||||||
isHourType = true;
|
|
||||||
method = parts[3];
|
|
||||||
if (parts.Length >= 5 && DateTime.TryParseExact(parts[4], "yyyyMMddHH", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt))
|
|
||||||
{
|
|
||||||
timestamp = dt;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (type == "day")
|
|
||||||
{
|
|
||||||
isHourType = false;
|
|
||||||
method = "DAILY";
|
|
||||||
string rawDate = "";
|
|
||||||
if (parts.Length >= 5)
|
|
||||||
{
|
|
||||||
machId = parts[3];
|
|
||||||
rawDate = parts[4];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rawDate = parts[3];
|
|
||||||
}
|
|
||||||
if (DateTime.TryParseExact(rawDate, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt))
|
|
||||||
{
|
|
||||||
timestamp = dt;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private record KeyMeta
|
private record KeyMeta
|
||||||
{
|
{
|
||||||
@@ -426,7 +487,5 @@ namespace MP.RIOC.Services
|
|||||||
public DateTime Timestamp = DateTime.MinValue;
|
public DateTime Timestamp = DateTime.MinValue;
|
||||||
public bool IsHourType = true;
|
public bool IsHourType = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Private Methods
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,9 +98,16 @@ namespace MP.RIOC.Services
|
|||||||
|
|
||||||
// ESECUZIONE FORWARDING
|
// ESECUZIONE FORWARDING
|
||||||
var error = await _forwarder.SendAsync(context, destBase, _httpClientInvoker, _forwarderConfig, HttpTransformer.Default, context.RequestAborted);
|
var error = await _forwarder.SendAsync(context, destBase, _httpClientInvoker, _forwarderConfig, HttpTransformer.Default, context.RequestAborted);
|
||||||
// commento transformer custom
|
// Se YARP fallisce per un problema di connessione interrotta (come l'errore 995)
|
||||||
//var error = await _forwarder.SendAsync(context, destBase, _httpClientInvoker, _forwarderConfig, _transformer, context.RequestAborted);
|
// e NON è un problema di sintassi della richiesta o di autorizzazione
|
||||||
|
if (error != ForwarderError.None &&
|
||||||
|
error != ForwarderError.RequestBodyClient &&
|
||||||
|
error != ForwarderError.NoAvailableDestinations)
|
||||||
|
{
|
||||||
|
// Fai un secondo e ultimo tentativo immediato prima di dare errore al client
|
||||||
|
Log.Warn($"Micro-reset di rete rilevato ({error}). Tento il secondo invio immediato...");
|
||||||
|
error = await _forwarder.SendAsync(context, destBase, _httpClientInvoker, _forwarderConfig, HttpTransformer.Default, context.RequestAborted);
|
||||||
|
}
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
_stats.RecordDuration(sKey, sw.Elapsed);
|
_stats.RecordDuration(sKey, sw.Elapsed);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
|
"Yarp": "Warning",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
|
"Yarp": "Warning",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Warning",
|
||||||
|
"Yarp": "Warning",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.AspNetCore": "Warning",
|
||||||
|
"Microsoft.AspNetCore.Hosting.Diagnostics": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NLog": {
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"logger": "Microsoft.*",
|
||||||
|
"maxLevel": "Fatal",
|
||||||
|
"final": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"logger": "Yarp.*",
|
||||||
|
"maxLevel": "Fatal",
|
||||||
|
"final": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"logger": "*",
|
||||||
|
"minLevel": "Info",
|
||||||
|
"writeTo": "logconsole"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"logger": "*",
|
||||||
|
"minLevel": "Info",
|
||||||
|
"writeTo": "logfile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Warning",
|
||||||
|
"Yarp": "Warning",
|
||||||
|
"Microsoft.EntityFrameworkCore": "Warning",
|
||||||
|
"Microsoft.AspNetCore.Hosting.Diagnostics": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NLog": {
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"logger": "Microsoft.AspNetCore.Hosting.Diagnostics",
|
||||||
|
"maxLevel": "Info",
|
||||||
|
"finalMinLevel": "Info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"logger": "*",
|
||||||
|
"minLevel": "Info",
|
||||||
|
"writeTo": "logfile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Warning",
|
||||||
|
"Yarp": "Warning",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.AspNetCore": "Warning",
|
||||||
|
"Microsoft.AspNetCore.Hosting.Diagnostics": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NLog": {
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"logger": "Microsoft.*",
|
||||||
|
"maxLevel": "Fatal",
|
||||||
|
"final": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"logger": "Yarp.*",
|
||||||
|
"maxLevel": "Fatal",
|
||||||
|
"final": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"logger": "*",
|
||||||
|
"minLevel": "Info",
|
||||||
|
"writeTo": "logconsole"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"logger": "*",
|
||||||
|
"minLevel": "Info",
|
||||||
|
"writeTo": "logfile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,10 +2,11 @@
|
|||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Yarp": "Debug",
|
"Yarp": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning",
|
"Microsoft.AspNetCore.Hosting.Diagnostics": "Information",
|
||||||
|
"Microsoft.EntityFrameworkCore.Database.Command": "Warning",
|
||||||
"Microsoft.EntityFrameworkCore": "Warning",
|
"Microsoft.EntityFrameworkCore": "Warning",
|
||||||
"Microsoft.EntityFrameworkCore.Database.Command": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
@@ -24,7 +25,7 @@
|
|||||||
"logfile": {
|
"logfile": {
|
||||||
"type": "File",
|
"type": "File",
|
||||||
"fileName": "${basedir}/logs/${shortdate}.log",
|
"fileName": "${basedir}/logs/${shortdate}.log",
|
||||||
"keepFileOpen": false,
|
"keepFileOpen": true,
|
||||||
"archiveEvery": "Day",
|
"archiveEvery": "Day",
|
||||||
"archiveFileName": "${basedir}/logs/old/${shortdate}_{#}.log",
|
"archiveFileName": "${basedir}/logs/old/${shortdate}_{#}.log",
|
||||||
"archiveNumbering": "DateAndSequence",
|
"archiveNumbering": "DateAndSequence",
|
||||||
@@ -39,9 +40,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rules": [
|
"rules": [
|
||||||
|
{
|
||||||
|
"logger": "Microsoft.EntityFrameworkCore.*",
|
||||||
|
"maxLevel": "Info",
|
||||||
|
"final": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"logger": "Microsoft.AspNetCore.Hosting.*",
|
||||||
|
"minLevel": "Info",
|
||||||
|
"finalMinLevel": "Info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"logger": "Microsoft.AspNetCore.*",
|
||||||
|
"maxLevel": "Info",
|
||||||
|
"finalMinLevel": "Info"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"logger": "*",
|
"logger": "*",
|
||||||
"minLevel": "Trace",
|
"minLevel": "Info",
|
||||||
"writeTo": "logconsole"
|
"writeTo": "logconsole"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Components;
|
|||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
using MP.AppAuth.Services;
|
using MP.AppAuth.Services;
|
||||||
|
using MP.Data.DbModels;
|
||||||
using MP.SPEC.Data;
|
using MP.SPEC.Data;
|
||||||
using MP.SPEC.Extensions;
|
using MP.SPEC.Extensions;
|
||||||
|
|
||||||
@@ -52,6 +53,14 @@ namespace MP.SPEC.Components
|
|||||||
|
|
||||||
protected async Task FlushCache()
|
protected async Task FlushCache()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// svuoto cache redis...
|
||||||
|
ConfigModel updRec = new ConfigModel()
|
||||||
|
{
|
||||||
|
Chiave = "AZIENDA",
|
||||||
|
Valore = "*"
|
||||||
|
};
|
||||||
|
await MDService.ConfigUpdateAsync(updRec);
|
||||||
await MDService.ForceFlushRedisCache();
|
await MDService.ForceFlushRedisCache();
|
||||||
await MDService.ForceFlushFusionCacheAsync();
|
await MDService.ForceFlushFusionCacheAsync();
|
||||||
await ForceReload();
|
await ForceReload();
|
||||||
@@ -122,7 +131,7 @@ namespace MP.SPEC.Components
|
|||||||
|
|
||||||
private void SetPageData()
|
private void SetPageData()
|
||||||
{
|
{
|
||||||
// update testo pagina da URI
|
// DoUpdate testo pagina da URI
|
||||||
string pageUri = NavManager.Page().ToLower();
|
string pageUri = NavManager.Page().ToLower();
|
||||||
// se home/index/vuoto... home!
|
// se home/index/vuoto... home!
|
||||||
if (string.IsNullOrEmpty(pageUri) || pageUri == "index" || pageUri == "home")
|
if (string.IsNullOrEmpty(pageUri) || pageUri == "index" || pageUri == "home")
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ namespace MP.SPEC.Components.Fermate
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Richiesta update
|
/// Richiesta DoUpdate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task RaiseRefresh()
|
private async Task RaiseRefresh()
|
||||||
|
|||||||
@@ -160,7 +160,6 @@ namespace MP.SPEC.Components
|
|||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
await Task.Delay(1);
|
|
||||||
// se sono cambiati --> rileggo...
|
// se sono cambiati --> rileggo...
|
||||||
if (!lastFilter.Equals(SelFilter))
|
if (!lastFilter.Equals(SelFilter))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
@using MP.SPEC.Components
|
@using MP.SPEC.Components
|
||||||
@using MP.SPEC.Components.ProdKit
|
@using MP.SPEC.Components.ProdKit
|
||||||
@using MP.SPEC.Data
|
|
||||||
|
|
||||||
@if (ListRecords == null || isLoading)
|
@if (ListRecords == null || isLoading)
|
||||||
{
|
{
|
||||||
@@ -24,7 +23,7 @@ else
|
|||||||
<th>
|
<th>
|
||||||
@if (currRecord != null)
|
@if (currRecord != null)
|
||||||
{
|
{
|
||||||
<button @onclick="() => resetSel(true)" class="btn btn-primary btn-sm"><i class="bi bi-arrow-counterclockwise"></i></button>
|
<button @onclick="() => DoResetSel(true)" class="btn btn-primary btn-sm"><i class="bi bi-arrow-counterclockwise"></i></button>
|
||||||
}
|
}
|
||||||
</th>
|
</th>
|
||||||
<th>Cod</th>
|
<th>Cod</th>
|
||||||
@@ -47,10 +46,10 @@ else
|
|||||||
<td class="text-nowrap" style="width: 8rem;">
|
<td class="text-nowrap" style="width: 8rem;">
|
||||||
@if (!(showRecipeConf || showRecipeArch))
|
@if (!(showRecipeConf || showRecipeArch))
|
||||||
{
|
{
|
||||||
<button @onclick="() => selRecord(record)" class="btn btn-primary btn-sm mx-0" title="Dettaglio Record"><i class="bi bi-check2"></i></button>
|
<button @onclick="() => DoSelRecord(record)" class="btn btn-primary btn-sm mx-0" title="Dettaglio Record"><i class="bi bi-check2"></i></button>
|
||||||
@if (!record.IsKit)
|
@if (!record.IsKit)
|
||||||
{
|
{
|
||||||
<button @onclick="() => cloneRecord(record)" class="btn btn-info btn-sm mx-0" title="Duplica Record"><i class="bi bi-clipboard-check"></i></button>
|
<button @onclick="() => DoCloneRecord(record)" class="btn btn-info btn-sm mx-0" title="Duplica Record"><i class="bi bi-clipboard-check"></i></button>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -60,7 +59,7 @@ else
|
|||||||
{
|
{
|
||||||
@if (!record.IsKit)
|
@if (!record.IsKit)
|
||||||
{
|
{
|
||||||
<button @onclick="() => editRecord(record)" class="btn btn-primary btn-sm mx-1" title="Modifica Record"><i class="bi bi-pencil-square"></i></button>
|
<button @onclick="() => DoEditRecord(record)" class="btn btn-primary btn-sm mx-1" title="Modifica Record"><i class="bi bi-pencil-square"></i></button>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -70,7 +69,7 @@ else
|
|||||||
{
|
{
|
||||||
@if (canStartOdl(record.IdxMacchina))
|
@if (canStartOdl(record.IdxMacchina))
|
||||||
{
|
{
|
||||||
<button @onclick="() => startOdl(record)" class="btn btn-success btn-sm mx-1" title="Avvia PODL">
|
<button @onclick="() => DoStartOdl(record)" class="btn btn-success btn-sm mx-1" title="Avvia PODL">
|
||||||
<i class="far fa-play-circle"></i>
|
<i class="far fa-play-circle"></i>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
@@ -93,13 +92,13 @@ else
|
|||||||
{
|
{
|
||||||
@if (machineHasRecipeConf(record.IdxMacchina))
|
@if (machineHasRecipeConf(record.IdxMacchina))
|
||||||
{
|
{
|
||||||
<button class="btn btn-dark btn-sm mx-0" title="Gestione Ricetta" @onclick="() => doShowRecipeConf(record)">
|
<button class="btn btn-dark btn-sm mx-0" title="Gestione Ricetta" @onclick="() => DoShowRecipeConf(record)">
|
||||||
<i class="fa-solid fa-flask"></i>
|
<i class="fa-solid fa-flask"></i>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
else if (machineHasRecipeArch(record.IdxMacchina))
|
else if (machineHasRecipeArch(record.IdxMacchina))
|
||||||
{
|
{
|
||||||
<button class="btn btn-primary btn-sm mx-0" title="Gestione Ricetta" @onclick="() => doShowRecipeArch(record)">
|
<button class="btn btn-primary btn-sm mx-0" title="Gestione Ricetta" @onclick="() => DoShowRecipeArch(record)">
|
||||||
<i class="fa-solid fa-flask"></i>
|
<i class="fa-solid fa-flask"></i>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
@@ -190,7 +189,7 @@ else
|
|||||||
<td>
|
<td>
|
||||||
@if (POdlDelEnabled(record.IdxOdl) && !record.IsKit)
|
@if (POdlDelEnabled(record.IdxOdl) && !record.IsKit)
|
||||||
{
|
{
|
||||||
<button @onclick="() => deleteRecord(record)" class="btn btn-danger btn-sm"><i class="bi bi-trash-fill"></i></button>
|
<button @onclick="() => DoDeleteRecord(record)" class="btn btn-danger btn-sm"><i class="bi bi-trash-fill"></i></button>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -208,13 +207,13 @@ else
|
|||||||
@if (showRecipeConf)
|
@if (showRecipeConf)
|
||||||
{
|
{
|
||||||
<div class="col-6 ps-0">
|
<div class="col-6 ps-0">
|
||||||
<RecipeConfMan IdxPODL="@currRecord.IdxPromessa" RecipePath="@currRecipePath" CancelEvent="resetSel"></RecipeConfMan>
|
<RecipeConfMan IdxPODL="@currRecord.IdxPromessa" RecipePath="@currRecipePath" CancelEvent="DoResetSel"></RecipeConfMan>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
else if (showRecipeArch)
|
else if (showRecipeArch)
|
||||||
{
|
{
|
||||||
<div class="col-6 ps-0">
|
<div class="col-6 ps-0">
|
||||||
<RecipeArchMan IdxPODL="@currRecord.IdxPromessa" RecipeCode="@currRecord.Recipe" RecipeArchPath="@currRecipeArchPath" IdxMacc="@currRecord.IdxMacchina" ReqCloseEvent="resetSel"></RecipeArchMan>
|
<RecipeArchMan IdxPODL="@currRecord.IdxPromessa" RecipeCode="@currRecord.Recipe" RecipeArchPath="@currRecipeArchPath" IdxMacc="@currRecord.IdxMacchina" ReqCloseEvent="DoResetSel"></RecipeArchMan>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,128 +52,13 @@ namespace MP.SPEC.Components
|
|||||||
|
|
||||||
#endregion Public Methods
|
#endregion Public Methods
|
||||||
|
|
||||||
#region Protected Fields
|
|
||||||
|
|
||||||
protected bool enableForceSync = true;
|
|
||||||
|
|
||||||
protected bool enableStartPODL = true;
|
|
||||||
|
|
||||||
protected bool enableStopODL = true;
|
|
||||||
|
|
||||||
#endregion Protected Fields
|
|
||||||
|
|
||||||
#region Protected Properties
|
|
||||||
|
|
||||||
protected string header
|
|
||||||
{
|
|
||||||
get => actFilter.Header;
|
|
||||||
set => actFilter.Header = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
protected IJSRuntime JSRuntime { get; set; } = null!;
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
protected MpDataService MDService { get; set; } = null!;
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
protected IOApiService MpIoApiCall { get; set; } = null!;
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
protected NavigationManager NavManager { get; set; } = null!;
|
|
||||||
|
|
||||||
#endregion Protected Properties
|
|
||||||
|
|
||||||
#region Protected Methods
|
#region Protected Methods
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Verifica se sia un articolo di tipo "KIT" x mostrare show dettaglio
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="CodArticolo"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected bool CheckIsKit(string CodArticolo)
|
|
||||||
{
|
|
||||||
bool answ = false;
|
|
||||||
if (ListArtKit != null && ListArtKit.Count > 0)
|
|
||||||
{
|
|
||||||
answ = ListArtKit.Count(x => x.CodArticolo == CodArticolo) > 0;
|
|
||||||
}
|
|
||||||
return answ;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task cloneRecord(PODLExpModel selRec)
|
|
||||||
{
|
|
||||||
currRecord = null;
|
|
||||||
// clono resettando ODL
|
|
||||||
var clonedRec = Utils.POdlExt.clone(selRec, true);
|
|
||||||
currRecord = clonedRec;
|
|
||||||
await RecordEdit.InvokeAsync(clonedRec);
|
|
||||||
header = "Duplica PODL";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Eliminazione record selezionato (previa conferma)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="selRec"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected async Task deleteRecord(PODLExpModel selRec)
|
|
||||||
{
|
|
||||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Eliminazione Record: sei sicuro di voler procedere?"))
|
|
||||||
return;
|
|
||||||
await Task.Delay(1);
|
|
||||||
var done = await MDService.POdlDeleteRecord(selRec);
|
|
||||||
await callSyncDb(selRec.IdxMacchina);
|
|
||||||
currRecord = null;
|
|
||||||
await ReloadDataAsync();
|
|
||||||
await Task.Delay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task doShowRecipeArch(PODLExpModel selRec)
|
|
||||||
{
|
|
||||||
currRecord = selRec;
|
|
||||||
currRecipeArchPath = await MDService.MacchineRecipeArchiveAsync(selRec.IdxMacchina);
|
|
||||||
showRecipeArch = true;
|
|
||||||
showRecipeConf = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task doShowRecipeConf(PODLExpModel selRec)
|
|
||||||
{
|
|
||||||
currRecord = selRec;
|
|
||||||
currRecipePath = await MDService.MacchineRecipeConfAsync(selRec.IdxMacchina);
|
|
||||||
showRecipeArch = false;
|
|
||||||
showRecipeConf = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task editRecord(PODLExpModel? selRec)
|
|
||||||
{
|
|
||||||
currRecord = selRec;
|
|
||||||
header = "Modifica PODL";
|
|
||||||
await RecordEdit.InvokeAsync(selRec);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task KitToggleDetailAsync(PODLExpModel? recSel)
|
|
||||||
{
|
|
||||||
if (recSel != null)
|
|
||||||
{
|
|
||||||
ListKitTemplate = await MDService.TemplateKitFiltAsync(recSel.CodArticolo, "");
|
|
||||||
ListPOdlKit = await MDService.POdlListByKitParentAsync(recSel.IdxPromessa);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ListKitTemplate = null;
|
|
||||||
ListPOdlKit = null;
|
|
||||||
}
|
|
||||||
showKitDetail = !showKitDetail;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await ReloadBaseData();
|
await ReloadBaseData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string? _lastPadCodXdl;
|
|
||||||
private bool _initialized;
|
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
// esempio: verifica parametri minimi
|
// esempio: verifica parametri minimi
|
||||||
@@ -196,207 +81,27 @@ namespace MP.SPEC.Components
|
|||||||
await InvokeAsync(() =>
|
await InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
PagerResetReq.InvokeAsync(true);
|
PagerResetReq.InvokeAsync(true);
|
||||||
Task task = UpdateData();
|
Task task = DoUpdateData();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool POdlDelEnabled(int idxOdl)
|
|
||||||
{
|
|
||||||
return idxOdl == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Caricamento dati di base
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected async Task ReloadBaseData()
|
|
||||||
{
|
|
||||||
ListRecords = null;
|
|
||||||
isLoading = true;
|
|
||||||
|
|
||||||
var list = await MDService.MachineWithOdlAsync();
|
|
||||||
_odlCurrSet = list.ToHashSet();
|
|
||||||
|
|
||||||
var machines = await MDService.MacchineGetFiltAsync("*");
|
|
||||||
|
|
||||||
_machinesWithConf = machines
|
|
||||||
.Where(x => !string.IsNullOrEmpty(x.RecipePath))
|
|
||||||
.Select(x => x.IdxMacchina)
|
|
||||||
.ToHashSet();
|
|
||||||
|
|
||||||
_machinesWithArch = machines
|
|
||||||
.Where(x => !string.IsNullOrEmpty(x.RecipeArchivePath))
|
|
||||||
.Select(x => x.IdxMacchina)
|
|
||||||
.ToHashSet();
|
|
||||||
|
|
||||||
ListStati = await MDService.AnagStatiCommAsync();
|
|
||||||
ListArtKit = await MDService.ArticoliGetByTipoAsync("KIT", "*");
|
|
||||||
string strMachRecipe = await MDService.ConfigTryGetAsync("MachineWithRecipe");
|
|
||||||
if (!string.IsNullOrEmpty(strMachRecipe))
|
|
||||||
{
|
|
||||||
bool.TryParse(strMachRecipe, out MachineWithRecipe);
|
|
||||||
}
|
|
||||||
string SPEC_PODL_gest = await MDService.ConfigTryGetAsync("SPEC_PODL_gest");
|
|
||||||
if (!string.IsNullOrEmpty(SPEC_PODL_gest))
|
|
||||||
{
|
|
||||||
bool.TryParse(SPEC_PODL_gest, out enableStartPODL);
|
|
||||||
}
|
|
||||||
string SPEC_ODL_gest = await MDService.ConfigTryGetAsync("SPEC_ODL_gest");
|
|
||||||
if (!string.IsNullOrEmpty(SPEC_ODL_gest))
|
|
||||||
{
|
|
||||||
bool.TryParse(SPEC_ODL_gest, out enableStopODL);
|
|
||||||
}
|
|
||||||
string SPEC_XODL_sync = await MDService.ConfigTryGetAsync("SPEC_XODL_sync");
|
|
||||||
if (!string.IsNullOrEmpty(SPEC_XODL_sync))
|
|
||||||
{
|
|
||||||
bool.TryParse(SPEC_XODL_sync, out enableForceSync);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task ReloadDataAsync()
|
|
||||||
{
|
|
||||||
isLoading = true;
|
|
||||||
ListRecords = null;
|
|
||||||
|
|
||||||
// ✅ lancia in parallelo
|
|
||||||
var odlTask = UpdateOdlList();
|
|
||||||
|
|
||||||
Task<List<PODLExpModel>> searchTask;
|
|
||||||
|
|
||||||
if (actFilter.ShowKit)
|
|
||||||
{
|
|
||||||
searchTask = MDService.POdlListGetFiltAsync(hasOdl, StatoSel, macchina, reparto, selDtStart, selDtEnd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
searchTask = MDService.POdlToKitListGetFiltAsync(hasOdl, StatoSel, macchina, reparto, selDtStart, selDtEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ aspetta tutto insieme
|
|
||||||
await Task.WhenAll(odlTask, searchTask);
|
|
||||||
var rawList = searchTask.Result;
|
|
||||||
// se abilitata ricerca filtro ulteriormente..
|
|
||||||
if (string.IsNullOrEmpty(actFilter.SearchVal))
|
|
||||||
{
|
|
||||||
SearchRecords = rawList;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SearchRecords = rawList
|
|
||||||
.Where(x =>
|
|
||||||
x.CodArticolo.Contains(actFilter.SearchVal, StringComparison.InvariantCulture)
|
|
||||||
|| x.CodFase.Contains(actFilter.SearchVal, StringComparison.InvariantCulture)
|
|
||||||
|| x.DescArticolo.Contains(actFilter.SearchVal, StringComparison.InvariantCulture)
|
|
||||||
).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
totalCount = SearchRecords.Count;
|
|
||||||
|
|
||||||
ListRecords = SearchRecords
|
|
||||||
.Skip(numRecord * (currPage - 1))
|
|
||||||
.Take(numRecord)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
isLoading = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task resetSel(bool forceUpdate)
|
|
||||||
{
|
|
||||||
currRecord = null;
|
|
||||||
currRecipePath = "";
|
|
||||||
showRecipeArch = false;
|
|
||||||
showRecipeConf = false;
|
|
||||||
if (forceUpdate)
|
|
||||||
{
|
|
||||||
await ReloadDataAsync();
|
|
||||||
}
|
|
||||||
await RecordEdit.InvokeAsync(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task selRecord(PODLExpModel? selRec)
|
|
||||||
{
|
|
||||||
currRecord = selRec;
|
|
||||||
header = "Dettaglio PODL";
|
|
||||||
await RecordSel.InvokeAsync(selRec);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task startOdl(PODLExpModel selRec)
|
|
||||||
{
|
|
||||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Sei sicuro di voler avviare PODL selezionato?"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (selRec != null)
|
|
||||||
{
|
|
||||||
int idxEvento = 0;
|
|
||||||
string evMess = "";
|
|
||||||
// verifico ancora NON ci sia ODL corrente/aperto
|
|
||||||
if (canStartOdl(selRec.IdxMacchina))
|
|
||||||
{
|
|
||||||
await callStartSetup(selRec.IdxMacchina);
|
|
||||||
await Task.Delay(1);
|
|
||||||
// chiamo stored stp_ODL_inizioSetupPromessa e recupero ODL corrente
|
|
||||||
bool fatto = await MDService.POdlDoSetup(selRec);
|
|
||||||
if (fatto)
|
|
||||||
{
|
|
||||||
var currPOdl = await MDService.POdlGetByKey(selRec.IdxPromessa);
|
|
||||||
var newOdl = await MDService.OdlByKeyAsync(currPOdl.IdxOdl);
|
|
||||||
//var newOdl = await MDService.OdlGetByKey(currPOdl.IdxOdl);
|
|
||||||
|
|
||||||
// registro evento...
|
|
||||||
idxEvento = 2;
|
|
||||||
evMess = $"Inizio Setup | PODL {selRec.IdxPromessa}";
|
|
||||||
processaEvento(selRec.IdxMacchina, idxEvento, evMess, newOdl.IdxOdl, newOdl.CodArticolo);
|
|
||||||
|
|
||||||
// aspetto 1 sec
|
|
||||||
await Task.Delay(1000);
|
|
||||||
|
|
||||||
// registro inizio produzione
|
|
||||||
idxEvento = 1;
|
|
||||||
evMess = $"Registrata inizio Produzione | PODL {selRec.IdxPromessa} | ODL {newOdl.IdxOdl} | ART {newOdl.CodArticolo}";
|
|
||||||
processaEvento(selRec.IdxMacchina, idxEvento, evMess, newOdl.IdxOdl, newOdl.CodArticolo);
|
|
||||||
|
|
||||||
// imposto task x setComm, setArt, SetPzComm
|
|
||||||
await callTask2Exe(selRec.IdxMacchina, "setArt", newOdl.CodArticolo);
|
|
||||||
string odlPad = newOdl.IdxOdl.ToString(padCodXdl);
|
|
||||||
await callTask2Exe(selRec.IdxMacchina, "setComm", $"ODL{odlPad}");
|
|
||||||
await callTask2Exe(selRec.IdxMacchina, "setPzComm", $"{newOdl.NumPezzi}");
|
|
||||||
await Task.Delay(1);
|
|
||||||
// chiamo task x IOB
|
|
||||||
await callForceUpdate(selRec.IdxMacchina);
|
|
||||||
//await Task.Delay(1);
|
|
||||||
//await callForceUpdate(selRec.IdxMacchina);
|
|
||||||
await Task.Delay(1);
|
|
||||||
await callSyncDb(selRec.IdxMacchina);
|
|
||||||
|
|
||||||
// svuoto memorie pagina...
|
|
||||||
await MDService.ForceFlushRedisCache();
|
|
||||||
// svuoto cache MpIoNsCache
|
|
||||||
await MDService.FlushRedisCacheMpIoOdl();
|
|
||||||
// svuoto altra cache
|
|
||||||
await MDService.ForceFlushFusionCacheAsync();
|
|
||||||
|
|
||||||
// ricarico pagina!
|
|
||||||
NavManager.NavigateTo(NavManager.Uri, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task UpdateData()
|
|
||||||
{
|
|
||||||
currRecord = null;
|
|
||||||
await ReloadDataAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Protected Methods
|
#endregion Protected Methods
|
||||||
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
private bool _initialized;
|
||||||
|
|
||||||
|
private string? _lastPadCodXdl;
|
||||||
|
|
||||||
private HashSet<string> _machinesWithArch = new();
|
private HashSet<string> _machinesWithArch = new();
|
||||||
|
|
||||||
private HashSet<string> _machinesWithConf = new();
|
private HashSet<string> _machinesWithConf = new();
|
||||||
|
|
||||||
private HashSet<string> _odlCurrSet = new();
|
private HashSet<string> _odlCurrSet = new();
|
||||||
|
|
||||||
private string currRecipeArchPath = "";
|
private string currRecipeArchPath = "";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -406,13 +111,21 @@ namespace MP.SPEC.Components
|
|||||||
|
|
||||||
private PODLExpModel? currRecord = null;
|
private PODLExpModel? currRecord = null;
|
||||||
|
|
||||||
|
private bool enableForceSync = true;
|
||||||
|
|
||||||
|
private bool enableStartPODL = true;
|
||||||
|
|
||||||
|
private bool enableStopODL = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Elenco articoli tipo KIT
|
/// Elenco articoli tipo KIT
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<AnagArticoliModel>? ListArtKit;
|
private List<AnagArticoliModel>? ListArtKit;
|
||||||
|
|
||||||
private List<TemplateKitModel>? ListKitTemplate = null;
|
private List<TemplateKitModel>? ListKitTemplate = null;
|
||||||
|
|
||||||
private List<PODLExpModel>? ListPOdlKit;
|
private List<PODLExpModel>? ListPOdlKit;
|
||||||
|
|
||||||
private List<PODLExpModel>? ListRecords;
|
private List<PODLExpModel>? ListRecords;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -433,8 +146,11 @@ namespace MP.SPEC.Components
|
|||||||
private List<string> odlCurrList = new List<string>();
|
private List<string> odlCurrList = new List<string>();
|
||||||
|
|
||||||
private List<PODLExpModel>? SearchRecords;
|
private List<PODLExpModel>? SearchRecords;
|
||||||
|
|
||||||
private bool showKitDetail = false;
|
private bool showKitDetail = false;
|
||||||
|
|
||||||
private bool showRecipeArch = false;
|
private bool showRecipeArch = false;
|
||||||
|
|
||||||
private bool showRecipeConf = false;
|
private bool showRecipeConf = false;
|
||||||
|
|
||||||
#endregion Private Fields
|
#endregion Private Fields
|
||||||
@@ -455,8 +171,17 @@ namespace MP.SPEC.Components
|
|||||||
set => actFilter.HasOdl = value;
|
set => actFilter.HasOdl = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string header
|
||||||
|
{
|
||||||
|
get => actFilter.Header;
|
||||||
|
set => actFilter.Header = value;
|
||||||
|
}
|
||||||
|
|
||||||
private bool isLoading { get; set; } = false;
|
private bool isLoading { get; set; } = false;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private IJSRuntime JSRuntime { get; set; } = null!;
|
||||||
|
|
||||||
private SelectXdlParams lastFilter { get; set; } = new SelectXdlParams() { CurrPage = -1 };
|
private SelectXdlParams lastFilter { get; set; } = new SelectXdlParams() { CurrPage = -1 };
|
||||||
|
|
||||||
private string macchina
|
private string macchina
|
||||||
@@ -470,6 +195,15 @@ namespace MP.SPEC.Components
|
|||||||
get => (showRecipeConf || showRecipeArch) ? "col-6" : "col-12";
|
get => (showRecipeConf || showRecipeArch) ? "col-6" : "col-12";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private MpDataService MDService { get; set; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private IOApiService MpIoApiCall { get; set; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private NavigationManager NavManager { get; set; } = null!;
|
||||||
|
|
||||||
private int numRecord
|
private int numRecord
|
||||||
{
|
{
|
||||||
get => actFilter.NumRec;
|
get => actFilter.NumRec;
|
||||||
@@ -611,12 +345,173 @@ namespace MP.SPEC.Components
|
|||||||
return !_odlCurrSet.Contains(idxMacchina);
|
return !_odlCurrSet.Contains(idxMacchina);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateOdlList()
|
/// <summary>
|
||||||
|
/// Verifica se sia un articolo di tipo "KIT" x mostrare show dettaglio
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="CodArticolo"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool CheckIsKit(string CodArticolo)
|
||||||
{
|
{
|
||||||
var list = await MDService.MachineWithOdlAsync();
|
bool answ = false;
|
||||||
_odlCurrSet = list.ToHashSet();
|
if (ListArtKit != null && ListArtKit.Count > 0)
|
||||||
|
{
|
||||||
|
answ = ListArtKit.Count(x => x.CodArticolo == CodArticolo) > 0;
|
||||||
|
}
|
||||||
|
return answ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task DoCloneRecord(PODLExpModel selRec)
|
||||||
|
{
|
||||||
|
currRecord = null;
|
||||||
|
// clono resettando ODL
|
||||||
|
var clonedRec = Utils.POdlExt.clone(selRec, true);
|
||||||
|
currRecord = clonedRec;
|
||||||
|
await RecordEdit.InvokeAsync(clonedRec);
|
||||||
|
header = "Duplica PODL";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Eliminazione record selezionato (previa conferma)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="selRec"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task DoDeleteRecord(PODLExpModel selRec)
|
||||||
|
{
|
||||||
|
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Eliminazione Record: sei sicuro di voler procedere?"))
|
||||||
|
return;
|
||||||
|
await Task.Delay(1);
|
||||||
|
var done = await MDService.POdlDeleteRecord(selRec);
|
||||||
|
await callSyncDb(selRec.IdxMacchina);
|
||||||
|
currRecord = null;
|
||||||
|
await ReloadDataAsync();
|
||||||
|
await Task.Delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoResetSel(bool forceUpdate)
|
||||||
|
{
|
||||||
|
currRecord = null;
|
||||||
|
currRecipePath = "";
|
||||||
|
showRecipeArch = false;
|
||||||
|
showRecipeConf = false;
|
||||||
|
if (forceUpdate)
|
||||||
|
{
|
||||||
|
await ReloadDataAsync();
|
||||||
|
}
|
||||||
|
await RecordEdit.InvokeAsync(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoSelRecord(PODLExpModel? selRec)
|
||||||
|
{
|
||||||
|
currRecord = selRec;
|
||||||
|
header = "Dettaglio PODL";
|
||||||
|
await RecordSel.InvokeAsync(selRec);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoShowRecipeArch(PODLExpModel selRec)
|
||||||
|
{
|
||||||
|
currRecord = selRec;
|
||||||
|
currRecipeArchPath = await MDService.MacchineRecipeArchiveAsync(selRec.IdxMacchina);
|
||||||
|
showRecipeArch = true;
|
||||||
|
showRecipeConf = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoShowRecipeConf(PODLExpModel selRec)
|
||||||
|
{
|
||||||
|
currRecord = selRec;
|
||||||
|
currRecipePath = await MDService.MacchineRecipeConfAsync(selRec.IdxMacchina);
|
||||||
|
showRecipeArch = false;
|
||||||
|
showRecipeConf = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoStartOdl(PODLExpModel selRec)
|
||||||
|
{
|
||||||
|
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Sei sicuro di voler avviare PODL selezionato?"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (selRec != null)
|
||||||
|
{
|
||||||
|
int idxEvento = 0;
|
||||||
|
string evMess = "";
|
||||||
|
// verifico ancora NON ci sia ODL corrente/aperto
|
||||||
|
if (canStartOdl(selRec.IdxMacchina))
|
||||||
|
{
|
||||||
|
await callStartSetup(selRec.IdxMacchina);
|
||||||
|
await Task.Delay(1);
|
||||||
|
// chiamo stored stp_ODL_inizioSetupPromessa e recupero ODL corrente
|
||||||
|
bool fatto = await MDService.POdlDoSetup(selRec);
|
||||||
|
if (fatto)
|
||||||
|
{
|
||||||
|
var currPOdl = await MDService.POdlGetByKey(selRec.IdxPromessa);
|
||||||
|
var newOdl = await MDService.OdlByKeyAsync(currPOdl.IdxOdl);
|
||||||
|
//var newOdl = await MDService.OdlGetByKey(currPOdl.IdxOdl);
|
||||||
|
|
||||||
|
// registro evento...
|
||||||
|
idxEvento = 2;
|
||||||
|
evMess = $"Inizio Setup | PODL {selRec.IdxPromessa}";
|
||||||
|
processaEvento(selRec.IdxMacchina, idxEvento, evMess, newOdl.IdxOdl, newOdl.CodArticolo);
|
||||||
|
|
||||||
|
// aspetto 1 sec
|
||||||
|
await Task.Delay(1000);
|
||||||
|
|
||||||
|
// registro inizio produzione
|
||||||
|
idxEvento = 1;
|
||||||
|
evMess = $"Registrata inizio Produzione | PODL {selRec.IdxPromessa} | ODL {newOdl.IdxOdl} | ART {newOdl.CodArticolo}";
|
||||||
|
processaEvento(selRec.IdxMacchina, idxEvento, evMess, newOdl.IdxOdl, newOdl.CodArticolo);
|
||||||
|
|
||||||
|
// imposto task x setComm, setArt, SetPzComm
|
||||||
|
await callTask2Exe(selRec.IdxMacchina, "setArt", newOdl.CodArticolo);
|
||||||
|
string odlPad = newOdl.IdxOdl.ToString(padCodXdl);
|
||||||
|
await callTask2Exe(selRec.IdxMacchina, "setComm", $"ODL{odlPad}");
|
||||||
|
await callTask2Exe(selRec.IdxMacchina, "setPzComm", $"{newOdl.NumPezzi}");
|
||||||
|
await Task.Delay(1);
|
||||||
|
// chiamo task x IOB
|
||||||
|
await callForceUpdate(selRec.IdxMacchina);
|
||||||
|
//await Task.Delay(1);
|
||||||
|
//await callForceUpdate(selRec.IdxMacchina);
|
||||||
|
await Task.Delay(1);
|
||||||
|
await callSyncDb(selRec.IdxMacchina);
|
||||||
|
|
||||||
|
// svuoto memorie pagina...
|
||||||
|
await MDService.ForceFlushRedisCache();
|
||||||
|
// svuoto cache MpIoNsCache
|
||||||
|
await MDService.FlushRedisCacheMpIoOdl();
|
||||||
|
// svuoto altra cache
|
||||||
|
await MDService.ForceFlushFusionCacheAsync();
|
||||||
|
|
||||||
|
// ricarico pagina!
|
||||||
|
NavManager.NavigateTo(NavManager.Uri, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoUpdateData()
|
||||||
|
{
|
||||||
|
currRecord = null;
|
||||||
|
await ReloadDataAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoEditRecord(PODLExpModel? selRec)
|
||||||
|
{
|
||||||
|
currRecord = selRec;
|
||||||
|
header = "Modifica PODL";
|
||||||
|
await RecordEdit.InvokeAsync(selRec);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task KitToggleDetailAsync(PODLExpModel? recSel)
|
||||||
|
{
|
||||||
|
if (recSel != null)
|
||||||
|
{
|
||||||
|
ListKitTemplate = await MDService.TemplateKitFiltAsync(recSel.CodArticolo, "");
|
||||||
|
ListPOdlKit = await MDService.POdlListByKitParentAsync(recSel.IdxPromessa);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ListKitTemplate = null;
|
||||||
|
ListPOdlKit = null;
|
||||||
|
}
|
||||||
|
showKitDetail = !showKitDetail;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifica se la idxMaccSel abbia associata un path x ricette (elenco)
|
/// Verifica se la idxMaccSel abbia associata un path x ricette (elenco)
|
||||||
@@ -638,6 +533,8 @@ namespace MP.SPEC.Components
|
|||||||
return _machinesWithConf.Contains(idxMacchina);
|
return _machinesWithConf.Contains(idxMacchina);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool POdlDelEnabled(int idxOdl) => idxOdl == 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// processa evento richiesto
|
/// processa evento richiesto
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -673,6 +570,95 @@ namespace MP.SPEC.Components
|
|||||||
await MDService.EvListInsert(newRec);
|
await MDService.EvListInsert(newRec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Caricamento dati di base
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task ReloadBaseData()
|
||||||
|
{
|
||||||
|
ListRecords = null;
|
||||||
|
isLoading = true;
|
||||||
|
|
||||||
|
var list = await MDService.MachineWithOdlAsync();
|
||||||
|
_odlCurrSet = list.ToHashSet();
|
||||||
|
|
||||||
|
var machines = await MDService.MacchineGetFiltAsync("*");
|
||||||
|
|
||||||
|
_machinesWithConf = machines
|
||||||
|
.Where(x => !string.IsNullOrEmpty(x.RecipePath))
|
||||||
|
.Select(x => x.IdxMacchina)
|
||||||
|
.ToHashSet();
|
||||||
|
|
||||||
|
_machinesWithArch = machines
|
||||||
|
.Where(x => !string.IsNullOrEmpty(x.RecipeArchivePath))
|
||||||
|
.Select(x => x.IdxMacchina)
|
||||||
|
.ToHashSet();
|
||||||
|
|
||||||
|
ListStati = await MDService.AnagStatiCommAsync();
|
||||||
|
ListArtKit = await MDService.ArticoliGetByTipoAsync("KIT", "*");
|
||||||
|
string strMachRecipe = await MDService.ConfigTryGetAsync("MachineWithRecipe");
|
||||||
|
if (!string.IsNullOrEmpty(strMachRecipe))
|
||||||
|
{
|
||||||
|
bool.TryParse(strMachRecipe, out MachineWithRecipe);
|
||||||
|
}
|
||||||
|
string SPEC_PODL_gest = await MDService.ConfigTryGetAsync("SPEC_PODL_gest");
|
||||||
|
if (!string.IsNullOrEmpty(SPEC_PODL_gest))
|
||||||
|
{
|
||||||
|
bool.TryParse(SPEC_PODL_gest, out enableStartPODL);
|
||||||
|
}
|
||||||
|
string SPEC_ODL_gest = await MDService.ConfigTryGetAsync("SPEC_ODL_gest");
|
||||||
|
if (!string.IsNullOrEmpty(SPEC_ODL_gest))
|
||||||
|
{
|
||||||
|
bool.TryParse(SPEC_ODL_gest, out enableStopODL);
|
||||||
|
}
|
||||||
|
string SPEC_XODL_sync = await MDService.ConfigTryGetAsync("SPEC_XODL_sync");
|
||||||
|
if (!string.IsNullOrEmpty(SPEC_XODL_sync))
|
||||||
|
{
|
||||||
|
bool.TryParse(SPEC_XODL_sync, out enableForceSync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ReloadDataAsync()
|
||||||
|
{
|
||||||
|
isLoading = true;
|
||||||
|
ListRecords = null;
|
||||||
|
|
||||||
|
// ✅ lancia in parallelo
|
||||||
|
var odlTask = UpdateOdlListAsync();
|
||||||
|
|
||||||
|
Task<List<PODLExpModel>> searchTask;
|
||||||
|
|
||||||
|
// imposto con sempre kit, opzionale kit child, opzionale attive
|
||||||
|
searchTask = MDService.POdlToKitListGetFiltAsync(hasOdl, StatoSel, macchina, reparto, selDtStart, selDtEnd, actFilter.IsActive, actFilter.ShowKit);
|
||||||
|
|
||||||
|
// ✅ aspetta tutto insieme
|
||||||
|
await Task.WhenAll(odlTask, searchTask);
|
||||||
|
var rawList = searchTask.Result;
|
||||||
|
// se abilitata ricerca filtro ulteriormente..
|
||||||
|
if (string.IsNullOrEmpty(actFilter.SearchVal))
|
||||||
|
{
|
||||||
|
SearchRecords = rawList;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SearchRecords = rawList
|
||||||
|
.Where(x =>
|
||||||
|
x.CodArticolo.Contains(actFilter.SearchVal, StringComparison.InvariantCulture)
|
||||||
|
|| x.CodFase.Contains(actFilter.SearchVal, StringComparison.InvariantCulture)
|
||||||
|
|| x.DescArticolo.Contains(actFilter.SearchVal, StringComparison.InvariantCulture)
|
||||||
|
).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCount = SearchRecords.Count;
|
||||||
|
|
||||||
|
ListRecords = SearchRecords
|
||||||
|
.Skip(numRecord * (currPage - 1))
|
||||||
|
.Take(numRecord)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
isLoading = false;
|
||||||
|
}
|
||||||
|
|
||||||
private string tradFase(string codFase)
|
private string tradFase(string codFase)
|
||||||
{
|
{
|
||||||
string answ = codFase;
|
string answ = codFase;
|
||||||
@@ -687,6 +673,12 @@ namespace MP.SPEC.Components
|
|||||||
return answ;
|
return answ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task UpdateOdlListAsync()
|
||||||
|
{
|
||||||
|
var list = await MDService.MachineWithOdlAsync();
|
||||||
|
_odlCurrSet = list.ToHashSet();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Private Methods
|
#endregion Private Methods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="px-2 input-group">
|
<div class="px-2 input-group">
|
||||||
<label class="input-group-text" for="macchina" title="Selezionare impianto"><i class="fa-solid fa-hard-drive"></i></label>
|
<label class="input-group-text" for="macchina" title="Selezionare impianto"><i class="fa-solid fa-hard-drive"></i></label>
|
||||||
<select @bind="@selMacchina" class="form-select" id="macchina" title="Selezionare impianto">
|
<select @bind="@selMacchina" @bind:after="ReportChangeMacc" class="form-select" id="macchina" title="Selezionare impianto">
|
||||||
<option value="*">--- Tutti ---</option>
|
<option value="*">--- Tutti ---</option>
|
||||||
@if (ListMacchine != null)
|
@if (ListMacchine != null)
|
||||||
{
|
{
|
||||||
@@ -102,21 +102,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="px-2 input-group">
|
<div class="px-2 input-group">
|
||||||
<label class="input-group-text" for="dtMin" title="Selezionare inizio periodo"><i class="fa-regular fa-calendar-minus"></i></label>
|
<label class="input-group-text" for="dtMin" title="Selezionare inizio periodo"><i class="fa-regular fa-calendar-minus"></i></label>
|
||||||
<input class="form-control" @bind="@selDtMin" id="dtMin" type="datetime-local" title="Data minima eventi da visualizzare">
|
<input class="form-control" @bind="@selDtMin" @bind:after="ReportChangeAsync" id="dtMin" type="datetime-local" title="Data minima eventi da visualizzare">
|
||||||
</div>
|
</div>
|
||||||
<div class="small mt-2">
|
<div class="small mt-2">
|
||||||
<label class="px-2" for="dtMax" title="Selezionare fine periodo">Fine Periodo</label>
|
<label class="px-2" for="dtMax" title="Selezionare fine periodo">Fine Periodo</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-2 input-group">
|
<div class="px-2 input-group">
|
||||||
<label class="input-group-text" for="dtMax" title="Selezionare fine periodo"><i class="fa-regular fa-calendar-plus"></i></label>
|
<label class="input-group-text" for="dtMax" title="Selezionare fine periodo"><i class="fa-regular fa-calendar-plus"></i></label>
|
||||||
<input class="form-control" @bind="@selDtMax" id="dtMax" type="datetime-local" title="Selezionare fine periodo">
|
<input class="form-control" @bind="@selDtMax" @bind:after="ReportChangeAsync" id="dtMax" type="datetime-local" title="Selezionare fine periodo">
|
||||||
</div>
|
</div>
|
||||||
<div class="small mt-2">
|
<div class="small mt-2">
|
||||||
<label class="px-2" for="tempoAgg" title="Selezionare refresh rate (sec) periodo">Refresh rate (sec)</label>
|
<label class="px-2" for="tempoAgg" title="Selezionare refresh rate (sec) periodo">Refresh rate (sec)</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-2 input-group">
|
<div class="px-2 input-group">
|
||||||
<label class="input-group-text" for="tempoAgg" title="Selezionare refresh rate (sec)"><i class="fa-solid fa-clock"></i></label>
|
<label class="input-group-text" for="tempoAgg" title="Selezionare refresh rate (sec)"><i class="fa-solid fa-clock"></i></label>
|
||||||
<select @bind="@selTempoAgg" class="form-select" id="tempoAgg" title="Selezionare refresh rate (sec)" style="width: 3em;">
|
<select @bind="@selTempoAgg" @bind:after="ReportChangeAsync" class="form-select" id="tempoAgg" title="Selezionare refresh rate (sec)" style="width: 3em;">
|
||||||
<option value="2">2</option>
|
<option value="2">2</option>
|
||||||
<option value="5">5</option>
|
<option value="5">5</option>
|
||||||
<option value="10">10</option>
|
<option value="10">10</option>
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="px-2 input-group">
|
<div class="px-2 input-group">
|
||||||
<label class="input-group-text" for="maxRecord" title="Numero massimo record da mostrare"><i class="fa-solid fa-list-ol"></i></label>
|
<label class="input-group-text" for="maxRecord" title="Numero massimo record da mostrare"><i class="fa-solid fa-list-ol"></i></label>
|
||||||
<select @bind="@selMaxRecord" class="form-select" id="maxRecord" title="Numero massimo record da mostrare">
|
<select @bind="@selMaxRecord" @bind:after="ReportChangeAsync" class="form-select" id="maxRecord" title="Numero massimo record da mostrare">
|
||||||
<option value="50">50</option>
|
<option value="50">50</option>
|
||||||
<option value="100">100</option>
|
<option value="100">100</option>
|
||||||
<option value="250">250</option>
|
<option value="250">250</option>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace MP.SPEC.Components
|
|||||||
snapshotDone = false;
|
snapshotDone = false;
|
||||||
aTimer.Stop();
|
aTimer.Stop();
|
||||||
aTimer.Enabled = false;
|
aTimer.Enabled = false;
|
||||||
//reportChange();
|
//ReportChangeAsync();
|
||||||
var pUpd = Task.Run(async () =>
|
var pUpd = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(1);
|
await Task.Delay(1);
|
||||||
@@ -71,7 +71,7 @@ namespace MP.SPEC.Components
|
|||||||
{
|
{
|
||||||
SelFilter.CurrPage = 0;
|
SelFilter.CurrPage = 0;
|
||||||
}
|
}
|
||||||
reportChange();
|
//ReportChangeAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,12 +91,13 @@ namespace MP.SPEC.Components
|
|||||||
{
|
{
|
||||||
SelFilter.CurrPage = 1;
|
SelFilter.CurrPage = 1;
|
||||||
SelFilter.CodFlux = value;
|
SelFilter.CodFlux = value;
|
||||||
StateHasChanged();
|
//StateHasChanged();
|
||||||
Task.Delay(1);
|
//Task.Delay(1);
|
||||||
reportChange();
|
//ReportChangeAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool showParam { get; set; } = false;
|
protected bool showParam { get; set; } = false;
|
||||||
protected bool selDt { get; set; } = false;
|
protected bool selDt { get; set; } = false;
|
||||||
protected string selMacchina
|
protected string selMacchina
|
||||||
@@ -109,14 +110,19 @@ namespace MP.SPEC.Components
|
|||||||
SelFilter.CurrPage = 1;
|
SelFilter.CurrPage = 1;
|
||||||
SelFilter.IdxMacchina = value;
|
SelFilter.IdxMacchina = value;
|
||||||
SelFilter.CodFlux = "*";
|
SelFilter.CodFlux = "*";
|
||||||
ListFlux = MDService.ParametriGetFiltAsync(selMacchina).Result;
|
//StateHasChanged();
|
||||||
StateHasChanged();
|
//Task.Delay(1);
|
||||||
Task.Delay(1);
|
//ReportChangeAsync();
|
||||||
reportChange();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ReportChangeMacc()
|
||||||
|
{
|
||||||
|
ListFlux = await MDService.ParametriGetFiltAsync(selMacchina);
|
||||||
|
await ReportChangeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
protected int selMaxRecord
|
protected int selMaxRecord
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -129,7 +135,7 @@ namespace MP.SPEC.Components
|
|||||||
if (!SelFilter.MaxRecord.Equals(value))
|
if (!SelFilter.MaxRecord.Equals(value))
|
||||||
{
|
{
|
||||||
SelFilter.MaxRecord = value;
|
SelFilter.MaxRecord = value;
|
||||||
reportChange();
|
//ReportChangeAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,7 +153,7 @@ namespace MP.SPEC.Components
|
|||||||
if (!SelFilter.TempoAgg.Equals(tempoMS))
|
if (!SelFilter.TempoAgg.Equals(tempoMS))
|
||||||
{
|
{
|
||||||
SelFilter.TempoAgg = tempoMS;
|
SelFilter.TempoAgg = tempoMS;
|
||||||
reportChange();
|
//ReportChangeAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,7 +187,8 @@ namespace MP.SPEC.Components
|
|||||||
setDtSnap();
|
setDtSnap();
|
||||||
DateTime dtStart = SelFilter.dtMin != null ? (DateTime)SelFilter.dtMin : DateTime.Now.AddMonths(-1);
|
DateTime dtStart = SelFilter.dtMin != null ? (DateTime)SelFilter.dtMin : DateTime.Now.AddMonths(-1);
|
||||||
DateTime dtEnd = SelFilter.dtMax != null ? (DateTime)SelFilter.dtMax : DateTime.Today.AddDays(1);
|
DateTime dtEnd = SelFilter.dtMax != null ? (DateTime)SelFilter.dtMax : DateTime.Today.AddDays(1);
|
||||||
ListMacchine = await MDService.MacchineWithFluxAsync(dtStart, dtEnd);
|
var rawListMacc = await MDService.MacchineWithFluxAsync(dtStart, dtEnd);
|
||||||
|
ListMacchine = rawListMacc.OrderBy(x => x).ToList();
|
||||||
ListFlux = await MDService.ParametriGetFiltAsync(selMacchina);
|
ListFlux = await MDService.ParametriGetFiltAsync(selMacchina);
|
||||||
|
|
||||||
var configData = await MDService.ConfigGetAllAsync();
|
var configData = await MDService.ConfigGetAllAsync();
|
||||||
@@ -295,7 +302,7 @@ namespace MP.SPEC.Components
|
|||||||
currFilt.lastUpdate = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss}";
|
currFilt.lastUpdate = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss}";
|
||||||
currFilt.dtMax = value;
|
currFilt.dtMax = value;
|
||||||
SelFilter = currFilt;
|
SelFilter = currFilt;
|
||||||
reportChange();
|
//ReportChangeAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -315,7 +322,7 @@ namespace MP.SPEC.Components
|
|||||||
currFilt.lastUpdate = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss}";
|
currFilt.lastUpdate = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss}";
|
||||||
currFilt.dtMin = value;
|
currFilt.dtMin = value;
|
||||||
SelFilter = currFilt;
|
SelFilter = currFilt;
|
||||||
reportChange();
|
//ReportChangeAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,7 +335,7 @@ namespace MP.SPEC.Components
|
|||||||
if (SelFilter.dtSnapMin != value)
|
if (SelFilter.dtSnapMin != value)
|
||||||
{
|
{
|
||||||
SelFilter.dtSnapMin = value;
|
SelFilter.dtSnapMin = value;
|
||||||
reportChange();
|
//ReportChangeAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,9 +351,9 @@ namespace MP.SPEC.Components
|
|||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
private void reportChange()
|
private async Task ReportChangeAsync()
|
||||||
{
|
{
|
||||||
FilterChanged.InvokeAsync(SelFilter);
|
await FilterChanged.InvokeAsync(SelFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Private Methods
|
#endregion Private Methods
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ namespace MP.SPEC.Components.ProdKit
|
|||||||
protected async Task toggleClosed()
|
protected async Task toggleClosed()
|
||||||
{
|
{
|
||||||
hasOdl = !hasOdl;
|
hasOdl = !hasOdl;
|
||||||
|
currPage = 1;
|
||||||
await EC_HasOdl.InvokeAsync(hasOdl);
|
await EC_HasOdl.InvokeAsync(hasOdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -220,12 +220,6 @@ namespace MP.SPEC.Components.ProdKit
|
|||||||
set => ActFilter.CurrPage = value;
|
set => ActFilter.CurrPage = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool hasOdl
|
|
||||||
{
|
|
||||||
get => ActFilter.HasOdl;
|
|
||||||
set => ActFilter.HasOdl = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool isLoading { get; set; } = false;
|
private bool isLoading { get; set; } = false;
|
||||||
|
|
||||||
private SelectXdlParams lastFilter { get; set; } = new SelectXdlParams() { CurrPage = -1 };
|
private SelectXdlParams lastFilter { get; set; } = new SelectXdlParams() { CurrPage = -1 };
|
||||||
|
|||||||
@@ -54,10 +54,10 @@
|
|||||||
</table>
|
</table>
|
||||||
}
|
}
|
||||||
<div runat="server" id="divPODL">
|
<div runat="server" id="divPODL">
|
||||||
<b>Elenco promesse per KIT (100%)</b>
|
<b>Elenco promesse KIT (100%)</b> da produrre
|
||||||
@if (ListRecPODL == null || ListRecPODL.Count == 0)
|
@if (ListRecPODL == null || ListRecPODL.Count == 0)
|
||||||
{
|
{
|
||||||
<div class="alert bg-success bg-opacity-25 fw-bold text-center">Nessuna PODL compatibile presente</div>
|
<div class="alert bg-success bg-opacity-25 fw-bold text-center">Nessuna PODL KIT presente</div>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ namespace MP.SPEC.Components.ProdKit
|
|||||||
|
|
||||||
// eseguo stored...
|
// eseguo stored...
|
||||||
bool fatto = await MDService.IstKitInsertByWKSAsync(currRec.CodArtParent, KeyFilt);
|
bool fatto = await MDService.IstKitInsertByWKSAsync(currRec.CodArtParent, KeyFilt);
|
||||||
// segnalo update
|
// segnalo DoUpdate
|
||||||
await EC_KitCreated.InvokeAsync(fatto);
|
await EC_KitCreated.InvokeAsync(fatto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ namespace MP.SPEC.Components.ProdKit
|
|||||||
{
|
{
|
||||||
if (selRec != null)
|
if (selRec != null)
|
||||||
{
|
{
|
||||||
// chiamo tentativo update!
|
// chiamo tentativo DoUpdate!
|
||||||
WipSetupKitModel newRec = new WipSetupKitModel()
|
WipSetupKitModel newRec = new WipSetupKitModel()
|
||||||
{
|
{
|
||||||
KeyFilt = keyFilt,
|
KeyFilt = keyFilt,
|
||||||
@@ -188,7 +188,7 @@ namespace MP.SPEC.Components.ProdKit
|
|||||||
{
|
{
|
||||||
listPOdlCheck = new List<PODLExpModel>();
|
listPOdlCheck = new List<PODLExpModel>();
|
||||||
listPOdlAct = await MDService.POdlListGetFiltAsync(ActFilt.HasOdl, ActFilt.CodFase, ActFilt.IdxMacchina, ActFilt.CodReparto, ActFilt.DtStart, ActFilt.DtEnd);
|
listPOdlAct = await MDService.POdlListGetFiltAsync(ActFilt.HasOdl, ActFilt.CodFase, ActFilt.IdxMacchina, ActFilt.CodReparto, ActFilt.DtStart, ActFilt.DtEnd);
|
||||||
listPOdl2Kit = await MDService.POdlToKitListGetFiltAsync(ActFilt.HasOdl, ActFilt.CodFase, ActFilt.IdxMacchina, ActFilt.CodReparto, ActFilt.DtStart, ActFilt.DtEnd);
|
listPOdl2Kit = await MDService.POdlToKitListGetFiltAsync(false, ActFilt.CodFase, ActFilt.IdxMacchina, ActFilt.CodReparto, ActFilt.DtStart, ActFilt.DtEnd, true, false);
|
||||||
listWSM = await MDService.WipKitFiltAsync(keyFilt);
|
listWSM = await MDService.WipKitFiltAsync(keyFilt);
|
||||||
listTSM = await MDService.TksScoreAsync(keyFilt, 1000, true);
|
listTSM = await MDService.TksScoreAsync(keyFilt, 1000, true);
|
||||||
listIKP = await MDService.IstKitFiltAsync("", "");
|
listIKP = await MDService.IstKitFiltAsync("", "");
|
||||||
|
|||||||
@@ -36,7 +36,10 @@
|
|||||||
<table class="table table-sm table-striped small">
|
<table class="table table-sm table-striped small">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@if (SelEnabled)
|
||||||
|
{
|
||||||
<th><button class="btn btn-sm btn-info" title="Reset" @onclick="DoReset"><i class="fa-solid fa-rotate"></i></button></th>
|
<th><button class="btn btn-sm btn-info" title="Reset" @onclick="DoReset"><i class="fa-solid fa-rotate"></i></button></th>
|
||||||
|
}
|
||||||
<th><i class="fa-solid fa-key"></i> Matr.</th>
|
<th><i class="fa-solid fa-key"></i> Matr.</th>
|
||||||
<th><i class="fa-solid fa-object-group"></i> Anagr.</th>
|
<th><i class="fa-solid fa-object-group"></i> Anagr.</th>
|
||||||
@if (DelEnabled)
|
@if (DelEnabled)
|
||||||
@@ -53,9 +56,13 @@
|
|||||||
@foreach (var item in ListRecords)
|
@foreach (var item in ListRecords)
|
||||||
{
|
{
|
||||||
<tr class="@cssRow(item)">
|
<tr class="@cssRow(item)">
|
||||||
|
|
||||||
|
@if (SelEnabled)
|
||||||
|
{
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-sm btn-info" title="Mostra Assegnazioni" @onclick="() => DoSelect(item)"><i class="fa-solid fa-search"></i></button>
|
<button class="btn btn-sm btn-info" title="Mostra Assegnazioni" @onclick="() => DoSelect(item)"><i class="fa-solid fa-search"></i></button>
|
||||||
</td>
|
</td>
|
||||||
|
}
|
||||||
<td class="@cssCol(item)">
|
<td class="@cssCol(item)">
|
||||||
<div>@item.MatrOpr</div>
|
<div>@item.MatrOpr</div>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ namespace MP.SPEC.Components.Reparti
|
|||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool DelEnabled { get; set; } = true;
|
public bool DelEnabled { get; set; } = true;
|
||||||
|
[Parameter]
|
||||||
|
public bool SelEnabled { get; set; } = true;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<bool> EC_RecChange { get; set; }
|
public EventCallback<bool> EC_RecChange { get; set; }
|
||||||
@@ -156,7 +158,7 @@ namespace MP.SPEC.Components.Reparti
|
|||||||
private async Task DoReset()
|
private async Task DoReset()
|
||||||
{
|
{
|
||||||
selRec = null;
|
selRec = null;
|
||||||
await EC_RecSel.InvokeAsync(null);
|
await EC_RecChange.InvokeAsync(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ReportUpdate(bool force)
|
private async Task ReportUpdate(bool force)
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ namespace MP.SPEC.Components.Reparti
|
|||||||
SelRecord = null;
|
SelRecord = null;
|
||||||
EditRec = null;
|
EditRec = null;
|
||||||
UpdateTable();
|
UpdateTable();
|
||||||
|
await EC_RecordUpdated.InvokeAsync(true);
|
||||||
await EC_RecordSel.InvokeAsync("");
|
await EC_RecordSel.InvokeAsync("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ namespace MP.SPEC.Components
|
|||||||
|
|
||||||
private async Task OnSelectionChanged(ChangeEventArgs e)
|
private async Task OnSelectionChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
Value = e.Value?.ToString();
|
Value = e.Value?.ToString() ?? "";
|
||||||
// Notifica il componente padre della variazione
|
// Notifica il componente padre della variazione
|
||||||
await ValueChanged.InvokeAsync(Value);
|
await ValueChanged.InvokeAsync(Value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (!isActive || hasOdl)
|
@if (true || !isActive || hasOdl)
|
||||||
{
|
{
|
||||||
<div class="small mt-2">
|
<div class="small mt-2">
|
||||||
<label class="px-2" for="dtMin" title="Selezionare inizio periodo">Inizio Periodo</label>
|
<label class="px-2" for="dtMin" title="Selezionare inizio periodo">Inizio Periodo</label>
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ namespace MP.SPEC.Controllers
|
|||||||
public RecipeArchiveController(IConfiguration configuration, MpDataService DataService)
|
public RecipeArchiveController(IConfiguration configuration, MpDataService DataService)
|
||||||
{
|
{
|
||||||
Log.Info("Starting RecipeArchiveController");
|
Log.Info("Starting RecipeArchiveController");
|
||||||
_configuration = configuration;
|
|
||||||
DService = DataService;
|
DService = DataService;
|
||||||
Log.Info("Avviata classe RecipeArchiveController");
|
Log.Info("Avviata classe RecipeArchiveController");
|
||||||
}
|
}
|
||||||
@@ -71,8 +70,6 @@ namespace MP.SPEC.Controllers
|
|||||||
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private static IConfiguration _configuration = null!;
|
|
||||||
|
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
#endregion Private Fields
|
#endregion Private Fields
|
||||||
|
|||||||
@@ -14,10 +14,9 @@ namespace MP.SPEC.Controllers
|
|||||||
{
|
{
|
||||||
#region Public Constructors
|
#region Public Constructors
|
||||||
|
|
||||||
public RecipeController(IConfiguration configuration, MpDataService DataService)
|
public RecipeController(MpDataService DataService)
|
||||||
{
|
{
|
||||||
Log.Info("Starting RecipeController");
|
Log.Info("Starting RecipeController");
|
||||||
_configuration = configuration;
|
|
||||||
DService = DataService;
|
DService = DataService;
|
||||||
Log.Info("Avviata classe RecipeController");
|
Log.Info("Avviata classe RecipeController");
|
||||||
}
|
}
|
||||||
@@ -66,8 +65,6 @@ namespace MP.SPEC.Controllers
|
|||||||
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private static IConfiguration _configuration = null!;
|
|
||||||
|
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
#endregion Private Fields
|
#endregion Private Fields
|
||||||
|
|||||||
@@ -25,12 +25,6 @@ namespace MP.SPEC.Data
|
|||||||
{
|
{
|
||||||
#region Public Constructors
|
#region Public Constructors
|
||||||
|
|
||||||
private readonly IAnagRepository _anagRepository;
|
|
||||||
private readonly ISystemRepository _systemRepository;
|
|
||||||
private readonly IDossierRepository _dossierRepository;
|
|
||||||
private readonly IFluxLogRepository _fluxLogRepository;
|
|
||||||
private readonly IProductionRepository _productionRepository;
|
|
||||||
|
|
||||||
public MpDataService(
|
public MpDataService(
|
||||||
IConnectionMultiplexer connMPlex,
|
IConnectionMultiplexer connMPlex,
|
||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
@@ -46,12 +40,6 @@ namespace MP.SPEC.Data
|
|||||||
redisConn = connMPlex;
|
redisConn = connMPlex;
|
||||||
redisDb = redisConn.GetDatabase();
|
redisDb = redisConn.GetDatabase();
|
||||||
|
|
||||||
#if false
|
|
||||||
// setup compoenti REDIS
|
|
||||||
redisConn = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("Redis") ?? "localhost:6379");
|
|
||||||
redisConnAdmin = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("RedisAdmin") ?? "localhost:6379");
|
|
||||||
redisDb = redisConn.GetDatabase();
|
|
||||||
#endif
|
|
||||||
// leggo cache lungo/cordo periodo
|
// leggo cache lungo/cordo periodo
|
||||||
int.TryParse(_configuration.GetValue<string>("ServerConf:redisShortTimeCache"), out redisShortTimeCache);
|
int.TryParse(_configuration.GetValue<string>("ServerConf:redisShortTimeCache"), out redisShortTimeCache);
|
||||||
int.TryParse(_configuration.GetValue<string>("ServerConf:redisLongTimeCache"), out redisLongTimeCache);
|
int.TryParse(_configuration.GetValue<string>("ServerConf:redisLongTimeCache"), out redisLongTimeCache);
|
||||||
@@ -376,15 +364,15 @@ namespace MP.SPEC.Data
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="currRec"></param>
|
/// <param name="currRec"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<bool> ArticoliUpdateRecord(AnagArticoliModel currRec)
|
public async Task<bool> ArticoliUpsertRecord(AnagArticoliModel currRec)
|
||||||
{
|
{
|
||||||
using var activity = ActivitySource.StartActivity("ArticoliUpdateRecord");
|
using var activity = ActivitySource.StartActivity("ArticoliUpsertRecord");
|
||||||
string source = "DB";
|
string source = "DB";
|
||||||
bool fatto = await _anagRepository.ArticoliUpdateRecord(currRec);
|
bool fatto = await _anagRepository.ArticoliUpsertAsync(currRec);
|
||||||
await FlushFusionCacheArticoli();
|
await FlushFusionCacheArticoli();
|
||||||
activity?.SetTag("data.source", source);
|
activity?.SetTag("data.source", source);
|
||||||
activity?.Stop();
|
activity?.Stop();
|
||||||
LogTrace($"ArticoliUpdateRecord | {source} | {activity?.Duration.TotalMilliseconds}ms");
|
LogTrace($"ArticoliUpsertRecord | {source} | {activity?.Duration.TotalMilliseconds}ms");
|
||||||
return fatto;
|
return fatto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -700,8 +688,13 @@ namespace MP.SPEC.Data
|
|||||||
/// Restitusice elenco Reparti
|
/// Restitusice elenco Reparti
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<List<RepartiDTO>> ElencoRepartiDtoAsync()
|
public async Task<List<RepartiDTO>> ElencoRepartiDtoAsync(bool forceReload)
|
||||||
{
|
{
|
||||||
|
if (forceReload)
|
||||||
|
{
|
||||||
|
await FlushFusionCacheMacGrp();
|
||||||
|
await FlushFusionCacheOprGrp();
|
||||||
|
}
|
||||||
return await GetOrFetchAsync(
|
return await GetOrFetchAsync(
|
||||||
operationName: "ElencoRepartiDtoAsync",
|
operationName: "ElencoRepartiDtoAsync",
|
||||||
cacheKey: $"{Utils.redisAnagGruppi}:REPARTO",
|
cacheKey: $"{Utils.redisAnagGruppi}:REPARTO",
|
||||||
@@ -710,20 +703,6 @@ namespace MP.SPEC.Data
|
|||||||
tagList: [Utils.redisAnagGruppi]
|
tagList: [Utils.redisAnagGruppi]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/// <summary>
|
|
||||||
/// Restitusice elenco Reparti
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<List<RepartiDTO>> GruppiRepartoDtoByOperAsync(int matrOpr)
|
|
||||||
{
|
|
||||||
return await GetOrFetchAsync(
|
|
||||||
operationName: "ElencoRepartiDtoAsync",
|
|
||||||
cacheKey: $"{Utils.redisAnagGruppiOpr}:{matrOpr}",
|
|
||||||
expiration: GetRandTOut(redisLongTimeCache),
|
|
||||||
fetchFunc: async () => await _anagRepository.GruppiRepartoDtoByOperAsync(matrOpr) ?? new(),
|
|
||||||
tagList: [Utils.redisAnagGruppiOpr]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Caricamento asincrono della cache degli articoli (Used/Unused)
|
/// Caricamento asincrono della cache degli articoli (Used/Unused)
|
||||||
@@ -780,6 +759,17 @@ namespace MP.SPEC.Data
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> FlushFusionCacheArticoli()
|
||||||
|
{
|
||||||
|
using var activity = ActivitySource.StartActivity("FlushFusionCacheArticoli");
|
||||||
|
string source = "FUSION";
|
||||||
|
bool answ = await FlushFusionCacheAsync(new List<string>() { Utils.redisArtList, Utils.redisArtByDossier });
|
||||||
|
activity?.SetTag("data.source", source);
|
||||||
|
activity?.Stop();
|
||||||
|
LogTrace($"FlushFusionCacheArticoli | {source} | {activity?.Duration.TotalMilliseconds}ms");
|
||||||
|
return answ;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flush cache relativa a MP-IO x dati ODL
|
/// Flush cache relativa a MP-IO x dati ODL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -952,6 +942,7 @@ namespace MP.SPEC.Data
|
|||||||
result = await _productionRepository.Grp2MaccDeleteAsync(rec2del);
|
result = await _productionRepository.Grp2MaccDeleteAsync(rec2del);
|
||||||
// elimino cache redis...
|
// elimino cache redis...
|
||||||
await FlushFusionCacheMacGrp();
|
await FlushFusionCacheMacGrp();
|
||||||
|
await FlushFusionCacheOprGrp();
|
||||||
activity?.SetTag("data.source", "DB");
|
activity?.SetTag("data.source", "DB");
|
||||||
activity?.Stop();
|
activity?.Stop();
|
||||||
LogTrace($"Grp2MaccDeleteAsync | CodGruppo {rec2del.CodGruppo} | IdxMacc {rec2del.IdxMacchina} | {activity?.Duration.TotalMilliseconds}ms");
|
LogTrace($"Grp2MaccDeleteAsync | CodGruppo {rec2del.CodGruppo} | IdxMacc {rec2del.IdxMacchina} | {activity?.Duration.TotalMilliseconds}ms");
|
||||||
@@ -970,6 +961,7 @@ namespace MP.SPEC.Data
|
|||||||
result = await _productionRepository.Grp2MaccInsertAsync(upsRec);
|
result = await _productionRepository.Grp2MaccInsertAsync(upsRec);
|
||||||
// elimino cache redis...
|
// elimino cache redis...
|
||||||
await FlushFusionCacheMacGrp();
|
await FlushFusionCacheMacGrp();
|
||||||
|
await FlushFusionCacheOprGrp();
|
||||||
activity?.SetTag("data.source", "DB");
|
activity?.SetTag("data.source", "DB");
|
||||||
activity?.Stop();
|
activity?.Stop();
|
||||||
LogTrace($"Grp2MaccInsertAsync | CodGruppo {upsRec.CodGruppo} | IdxMacc {upsRec.IdxMacchina} | {activity?.Duration.TotalMilliseconds}ms");
|
LogTrace($"Grp2MaccInsertAsync | CodGruppo {upsRec.CodGruppo} | IdxMacc {upsRec.IdxMacchina} | {activity?.Duration.TotalMilliseconds}ms");
|
||||||
@@ -987,6 +979,7 @@ namespace MP.SPEC.Data
|
|||||||
bool result = false;
|
bool result = false;
|
||||||
result = await _productionRepository.Grp2OperDeleteAsync(rec2del);
|
result = await _productionRepository.Grp2OperDeleteAsync(rec2del);
|
||||||
// elimino cache redis...
|
// elimino cache redis...
|
||||||
|
await FlushFusionCacheMacGrp();
|
||||||
await FlushFusionCacheOprGrp();
|
await FlushFusionCacheOprGrp();
|
||||||
activity?.SetTag("data.source", "DB");
|
activity?.SetTag("data.source", "DB");
|
||||||
activity?.Stop();
|
activity?.Stop();
|
||||||
@@ -1005,6 +998,7 @@ namespace MP.SPEC.Data
|
|||||||
bool result = false;
|
bool result = false;
|
||||||
result = await _productionRepository.Grp2OperInsertAsync(upsRec);
|
result = await _productionRepository.Grp2OperInsertAsync(upsRec);
|
||||||
// elimino cache redis...
|
// elimino cache redis...
|
||||||
|
await FlushFusionCacheMacGrp();
|
||||||
await FlushFusionCacheOprGrp();
|
await FlushFusionCacheOprGrp();
|
||||||
activity?.SetTag("data.source", "DB");
|
activity?.SetTag("data.source", "DB");
|
||||||
activity?.Stop();
|
activity?.Stop();
|
||||||
@@ -1012,6 +1006,21 @@ namespace MP.SPEC.Data
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restitusice elenco Reparti
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<List<RepartiDTO>> GruppiRepartoDtoByOperAsync(int matrOpr)
|
||||||
|
{
|
||||||
|
return await GetOrFetchAsync(
|
||||||
|
operationName: "ElencoRepartiDtoAsync",
|
||||||
|
cacheKey: $"{Utils.redisAnagGruppiOpr}:{matrOpr}",
|
||||||
|
expiration: GetRandTOut(redisLongTimeCache),
|
||||||
|
fetchFunc: async () => await _anagRepository.GruppiRepartoDtoByOperAsync(matrOpr) ?? new(),
|
||||||
|
tagList: [Utils.redisAnagGruppiOpr]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Init ricetta
|
/// Init ricetta
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1442,7 +1451,8 @@ namespace MP.SPEC.Data
|
|||||||
bool fatto = false;
|
bool fatto = false;
|
||||||
// salvo
|
// salvo
|
||||||
fatto = await _productionRepository.OperatoriUpsertAsync(updRec);
|
fatto = await _productionRepository.OperatoriUpsertAsync(updRec);
|
||||||
await FlushFusionCacheAsync(Utils.redisOprList);
|
await FlushFusionCacheMacGrp();
|
||||||
|
await FlushFusionCacheOprGrp();
|
||||||
activity?.SetTag("data.source", source);
|
activity?.SetTag("data.source", source);
|
||||||
activity?.Stop();
|
activity?.Stop();
|
||||||
LogTrace($"OperatoriUpsertAsync | {source} | {activity?.Duration.TotalMilliseconds}ms");
|
LogTrace($"OperatoriUpsertAsync | {source} | {activity?.Duration.TotalMilliseconds}ms");
|
||||||
@@ -1669,10 +1679,15 @@ namespace MP.SPEC.Data
|
|||||||
/// <param name="codGruppo">Gruppo</param>
|
/// <param name="codGruppo">Gruppo</param>
|
||||||
/// <param name="startDate">Data inizio</param>
|
/// <param name="startDate">Data inizio</param>
|
||||||
/// <param name="endDate">Data fine</param>
|
/// <param name="endDate">Data fine</param>
|
||||||
|
/// <param name="flagAttive">se true = solo attive</param>
|
||||||
|
/// <param name="flagKitChild">se true = mostra Kit Child</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<List<PODLExpModel>> POdlToKitListGetFiltAsync(bool lanciato, string keyRichPart, string idxMacchina, string codGruppo, DateTime startDate, DateTime endDate)
|
public async Task<List<PODLExpModel>> POdlToKitListGetFiltAsync(bool lanciato, string keyRichPart, string idxMacchina, string codGruppo, DateTime startDate, DateTime endDate, bool flagAttive, bool flagKitChild)
|
||||||
{
|
{
|
||||||
string redisKey = $"{Utils.redisPOdlList}_kit:{codGruppo}:{idxMacchina}:{keyRichPart}:{lanciato}:{startDate:yyyyMMdd_HHmmss}:{endDate:yyyyMMdd_HHmmss}";
|
string codLanc = lanciato ? "ALL" : "READY";
|
||||||
|
string codFlagAtt = flagAttive ? "ACT" : "ALL";
|
||||||
|
string codFlagKCh = flagKitChild ? "KALL" : "KP";
|
||||||
|
string redisKey = $"{Utils.redisPOdlList}_kit:{codGruppo}:{idxMacchina}:{keyRichPart}:{codLanc}:{codFlagAtt}:{codFlagKCh}:{startDate:yyyyMMdd_HHmmss}:{endDate:yyyyMMdd_HHmmss}";
|
||||||
|
|
||||||
return await GetOrFetchAsync(
|
return await GetOrFetchAsync(
|
||||||
operationName: "POdlToKitListGetFiltAsync",
|
operationName: "POdlToKitListGetFiltAsync",
|
||||||
@@ -1685,7 +1700,9 @@ namespace MP.SPEC.Data
|
|||||||
idxMacchina,
|
idxMacchina,
|
||||||
codGruppo,
|
codGruppo,
|
||||||
startDate,
|
startDate,
|
||||||
endDate
|
endDate,
|
||||||
|
flagAttive,
|
||||||
|
flagKitChild
|
||||||
) ?? new List<PODLExpModel>(),
|
) ?? new List<PODLExpModel>(),
|
||||||
tagList: [Utils.redisPOdlList, $"{Utils.redisPOdlList}_kit"]
|
tagList: [Utils.redisPOdlList, $"{Utils.redisPOdlList}_kit"]
|
||||||
);
|
);
|
||||||
@@ -1909,7 +1926,7 @@ namespace MP.SPEC.Data
|
|||||||
return await GetOrFetchAsync(
|
return await GetOrFetchAsync(
|
||||||
operationName: "TksScoreAsync",
|
operationName: "TksScoreAsync",
|
||||||
cacheKey: currKey,
|
cacheKey: currKey,
|
||||||
expiration: TimeSpan.FromMinutes(redisLongTimeCache),
|
expiration: GetRandTOut(redisLongTimeCache),
|
||||||
fetchFunc: async () => await _productionRepository.TksScoreAsync(KeyFilt, MaxResult) ?? new List<TksScoreModel>(),
|
fetchFunc: async () => await _productionRepository.TksScoreAsync(KeyFilt, MaxResult) ?? new List<TksScoreModel>(),
|
||||||
tagList: [Utils.redisKitScore]
|
tagList: [Utils.redisKitScore]
|
||||||
);
|
);
|
||||||
@@ -1999,7 +2016,7 @@ namespace MP.SPEC.Data
|
|||||||
return await GetOrFetchAsync(
|
return await GetOrFetchAsync(
|
||||||
operationName: "WipKitFiltAsync",
|
operationName: "WipKitFiltAsync",
|
||||||
cacheKey: currKey,
|
cacheKey: currKey,
|
||||||
expiration: TimeSpan.FromMinutes(redisLongTimeCache),
|
expiration: GetRandTOut(redisLongTimeCache),
|
||||||
fetchFunc: async () => await _productionRepository.WipKitFiltAsync(KeyFilt) ?? new List<WipSetupKitModel>(),
|
fetchFunc: async () => await _productionRepository.WipKitFiltAsync(KeyFilt) ?? new List<WipSetupKitModel>(),
|
||||||
tagList: [Utils.redisKitWip]
|
tagList: [Utils.redisKitWip]
|
||||||
);
|
);
|
||||||
@@ -2018,6 +2035,7 @@ namespace MP.SPEC.Data
|
|||||||
fatto = await _productionRepository.WipKitUpsertAsync(currRecord);
|
fatto = await _productionRepository.WipKitUpsertAsync(currRecord);
|
||||||
// svuoto cache KitWip
|
// svuoto cache KitWip
|
||||||
await FlushFusionCacheAsync(Utils.redisKitWip);
|
await FlushFusionCacheAsync(Utils.redisKitWip);
|
||||||
|
await FlushFusionCacheAsync(Utils.redisKitScore);
|
||||||
activity?.SetTag("data.source", source);
|
activity?.SetTag("data.source", source);
|
||||||
activity?.Stop();
|
activity?.Stop();
|
||||||
LogTrace($"WipKitUpsertAsync | {source} | {activity?.Duration.TotalMilliseconds}ms");
|
LogTrace($"WipKitUpsertAsync | {source} | {activity?.Duration.TotalMilliseconds}ms");
|
||||||
@@ -2034,11 +2052,13 @@ namespace MP.SPEC.Data
|
|||||||
private static readonly ActivitySource ActivitySource = new ActivitySource("MP.DATA.Tracer");
|
private static readonly ActivitySource ActivitySource = new ActivitySource("MP.DATA.Tracer");
|
||||||
|
|
||||||
private static IConfiguration _configuration = null!;
|
private static IConfiguration _configuration = null!;
|
||||||
|
|
||||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
private readonly IAnagRepository _anagRepository;
|
||||||
private readonly IFusionCache _cache;
|
private readonly IFusionCache _cache;
|
||||||
|
private readonly IDossierRepository _dossierRepository;
|
||||||
|
private readonly IFluxLogRepository _fluxLogRepository;
|
||||||
|
private readonly IProductionRepository _productionRepository;
|
||||||
|
private readonly ISystemRepository _systemRepository;
|
||||||
private DateTime _artCacheExpiry = DateTime.MinValue;
|
private DateTime _artCacheExpiry = DateTime.MinValue;
|
||||||
|
|
||||||
private Dictionary<string, string> _configData = new();
|
private Dictionary<string, string> _configData = new();
|
||||||
@@ -2100,8 +2120,6 @@ namespace MP.SPEC.Data
|
|||||||
|
|
||||||
#region Private Properties
|
#region Private Properties
|
||||||
|
|
||||||
private static MpSpecController dbController { get; set; } = null!;
|
|
||||||
|
|
||||||
private static MpMongoController mongoController { get; set; } = null!;
|
private static MpMongoController mongoController { get; set; } = null!;
|
||||||
|
|
||||||
#endregion Private Properties
|
#endregion Private Properties
|
||||||
@@ -2170,17 +2188,6 @@ namespace MP.SPEC.Data
|
|||||||
return answ;
|
return answ;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> FlushFusionCacheArticoli()
|
|
||||||
{
|
|
||||||
using var activity = ActivitySource.StartActivity("FlushFusionCacheArticoli");
|
|
||||||
string source = "FUSION";
|
|
||||||
bool answ = await FlushFusionCacheAsync(new List<string>() { Utils.redisArtList, Utils.redisArtByDossier });
|
|
||||||
activity?.SetTag("data.source", source);
|
|
||||||
activity?.Stop();
|
|
||||||
LogTrace($"FlushFusionCacheArticoli | {source} | {activity?.Duration.TotalMilliseconds}ms");
|
|
||||||
return answ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cancellazione FusionCache (totale)
|
/// Cancellazione FusionCache (totale)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2196,6 +2203,7 @@ namespace MP.SPEC.Data
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cancellazione FusionCache dato singolo tag
|
/// Cancellazione FusionCache dato singolo tag
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="tag"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task<bool> FlushFusionCacheAsync(string tag)
|
private async Task<bool> FlushFusionCacheAsync(string tag)
|
||||||
{
|
{
|
||||||
@@ -2209,6 +2217,7 @@ namespace MP.SPEC.Data
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cancellazione FusionCache dato elenco tags
|
/// Cancellazione FusionCache dato elenco tags
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="listTags"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task<bool> FlushFusionCacheAsync(List<string> listTags)
|
private async Task<bool> FlushFusionCacheAsync(List<string> listTags)
|
||||||
{
|
{
|
||||||
@@ -2279,7 +2288,7 @@ namespace MP.SPEC.Data
|
|||||||
{
|
{
|
||||||
using var activity = ActivitySource.StartActivity("FlushFusionCacheOprGrp");
|
using var activity = ActivitySource.StartActivity("FlushFusionCacheOprGrp");
|
||||||
string source = "FUSION";
|
string source = "FUSION";
|
||||||
bool answ = await FlushFusionCacheAsync(new List<string> { Utils.redisAnagGruppi, Utils.redisOprList });
|
bool answ = await FlushFusionCacheAsync(new List<string> { Utils.redisAnagGruppi, Utils.redisOprList, Utils.redisAnagGruppiOpr });
|
||||||
activity?.SetTag("data.source", source);
|
activity?.SetTag("data.source", source);
|
||||||
activity?.Stop();
|
activity?.Stop();
|
||||||
LogTrace($"FlushFusionCacheOprGrp | {source} | {activity?.Duration.TotalMilliseconds}ms");
|
LogTrace($"FlushFusionCacheOprGrp | {source} | {activity?.Duration.TotalMilliseconds}ms");
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#region Public Properties
|
#region Public Properties
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Bool: indica se il toggleClosed è attivo
|
/// Bool: indica se il DoToggleClosed è attivo
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool isActive { get; set; } = true;
|
public bool isActive { get; set; } = true;
|
||||||
|
|
||||||
|
|||||||
@@ -42,12 +42,13 @@ namespace MP.SPEC.Data
|
|||||||
DtEnd = this.DtEnd,
|
DtEnd = this.DtEnd,
|
||||||
DtStart = this.DtStart,
|
DtStart = this.DtStart,
|
||||||
HasOdl = this.HasOdl,
|
HasOdl = this.HasOdl,
|
||||||
|
Header = this.Header,
|
||||||
IdxMacchina = this.IdxMacchina,
|
IdxMacchina = this.IdxMacchina,
|
||||||
IsActive = this.IsActive,
|
IsActive = this.IsActive,
|
||||||
MaxRecord = this.MaxRecord,
|
MaxRecord = this.MaxRecord,
|
||||||
NumRec = this.NumRec,
|
NumRec = this.NumRec,
|
||||||
SearchVal = this.SearchVal,
|
SearchVal = this.SearchVal,
|
||||||
Header = this.Header,
|
ShowKit = this.ShowKit,
|
||||||
TotCount = this.TotCount
|
TotCount = this.TotCount
|
||||||
};
|
};
|
||||||
return clonedData;
|
return clonedData;
|
||||||
@@ -82,6 +83,9 @@ namespace MP.SPEC.Data
|
|||||||
if (IsActive != item.IsActive)
|
if (IsActive != item.IsActive)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (ShowKit != item.ShowKit)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (MaxRecord != item.MaxRecord)
|
if (MaxRecord != item.MaxRecord)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -90,6 +94,7 @@ namespace MP.SPEC.Data
|
|||||||
|
|
||||||
if (SearchVal != item.SearchVal)
|
if (SearchVal != item.SearchVal)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (Header != item.Header)
|
if (Header != item.Header)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<RootNamespace>MP.SPEC</RootNamespace>
|
<RootNamespace>MP.SPEC</RootNamespace>
|
||||||
<Version>8.16.2606.408</Version>
|
<Version>8.16.2606.1218</Version>
|
||||||
<UserSecretsId>1800a78a-6ff1-40f9-b490-87fb8bfc1394</UserSecretsId>
|
<UserSecretsId>1800a78a-6ff1-40f9-b490-87fb8bfc1394</UserSecretsId>
|
||||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
@page "/ART"
|
@page "/ART"
|
||||||
|
|
||||||
@using MP.SPEC.Components
|
|
||||||
@using MP.SPEC.Data
|
|
||||||
|
|
||||||
<div class="card mb-5">
|
<div class="card mb-5">
|
||||||
<div class="card-header table-primary">
|
<div class="card-header table-primary">
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
@@ -158,7 +155,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
@if (ListRecords == null || isLoading)
|
@if (isLoading && false)
|
||||||
{
|
{
|
||||||
<LoadingData></LoadingData>
|
<LoadingData></LoadingData>
|
||||||
}
|
}
|
||||||
@@ -176,7 +173,7 @@
|
|||||||
<th>
|
<th>
|
||||||
@if (currRecord != null)
|
@if (currRecord != null)
|
||||||
{
|
{
|
||||||
<button @onclick="() => resetSel()" class="btn btn-primary btn-sm"><i class="bi bi-arrow-counterclockwise"></i></button>
|
<button @onclick="ResetSel" class="btn btn-primary btn-sm"><i class="bi bi-arrow-counterclockwise"></i></button>
|
||||||
}
|
}
|
||||||
</th>
|
</th>
|
||||||
<th><i class="fa-solid fa-file"></i> Articolo</th>
|
<th><i class="fa-solid fa-file"></i> Articolo</th>
|
||||||
|
|||||||
+154
-161
@@ -28,20 +28,88 @@ namespace MP.SPEC.Pages
|
|||||||
|
|
||||||
#endregion Public Methods
|
#endregion Public Methods
|
||||||
|
|
||||||
#region Protected Properties
|
#region Protected Methods
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
numRecord = 10;
|
||||||
|
await ReloadBaseData();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync()
|
||||||
|
{
|
||||||
|
await ReloadDataAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Protected Methods
|
||||||
|
|
||||||
|
#region Private Fields
|
||||||
|
|
||||||
|
private int _currPage = 1;
|
||||||
|
private int _numRecord = 10;
|
||||||
|
private string _selAzienda = "*";
|
||||||
|
private int availRecord = 1000;
|
||||||
|
private SelectArticoliParams currFilter = new SelectArticoliParams();
|
||||||
|
private AnagArticoliModel? currRecord = null;
|
||||||
|
private bool isLoading = false;
|
||||||
|
private bool isNewArt = false;
|
||||||
|
private List<AnagGruppiModel>? ListAziende;
|
||||||
|
private List<AnagArticoliModel>? ListRecords;
|
||||||
|
private List<ListValuesModel>? ListTipoArt;
|
||||||
|
private int maxNumRecord = 1000;
|
||||||
|
private List<AnagArticoliModel>? SearchRecords;
|
||||||
|
private string selTipoArt = "*";
|
||||||
|
private int totalCount = 0;
|
||||||
|
|
||||||
|
#endregion Private Fields
|
||||||
|
|
||||||
|
#region Private Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifica cablata x add tutto tranne KIT
|
||||||
|
/// </summary>
|
||||||
|
private bool CanAdd => !selTipoArt.Equals("KIT");
|
||||||
|
|
||||||
|
private int currPage
|
||||||
|
{
|
||||||
|
get => _currPage;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_currPage != value)
|
||||||
|
{
|
||||||
|
_currPage = value;
|
||||||
|
UpdateTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
protected IJSRuntime JSRuntime { get; set; } = null!;
|
private IJSRuntime JSRuntime { get; set; } = null!;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
protected MpDataService MDService { get; set; } = null!;
|
private MpDataService MDService { get; set; } = null!;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
protected NavigationManager NavManager { get; set; } = null!;
|
private NavigationManager NavManager { get; set; } = null!;
|
||||||
|
|
||||||
|
private int numRecord
|
||||||
|
{
|
||||||
|
get => _numRecord;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_numRecord != value)
|
||||||
|
{
|
||||||
|
_numRecord = value;
|
||||||
|
UpdateTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string searchCss => string.IsNullOrEmpty(searchVal) ? "btn-secondary" : "btn-primary";
|
private string searchCss => string.IsNullOrEmpty(searchVal) ? "btn-secondary" : "btn-primary";
|
||||||
|
|
||||||
protected string SearchVal
|
private string searchVal { get; set; } = "";
|
||||||
|
|
||||||
|
private string SearchVal
|
||||||
{
|
{
|
||||||
get => searchVal;
|
get => searchVal;
|
||||||
set
|
set
|
||||||
@@ -54,17 +122,29 @@ namespace MP.SPEC.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int totalCount = 0;
|
private string selAzienda
|
||||||
|
{
|
||||||
|
get => _selAzienda;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _selAzienda)
|
||||||
|
{
|
||||||
|
_selAzienda = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Protected Properties
|
private bool ShowCharts { get; set; } = false;
|
||||||
|
|
||||||
#region Protected Methods
|
#endregion Private Properties
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Crea nuovo record e va in editing...
|
/// Crea nuovo record e va in editing...
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected void AddNew()
|
private void AddNew()
|
||||||
{
|
{
|
||||||
isNewArt = true;
|
isNewArt = true;
|
||||||
currRecord = new AnagArticoliModel()
|
currRecord = new AnagArticoliModel()
|
||||||
@@ -79,11 +159,24 @@ namespace MP.SPEC.Pages
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifica cancellabilità record
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="selRec"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool ArticoloDelEnabled(AnagArticoliModel currRec)
|
||||||
|
{
|
||||||
|
if (currRec.Tipo.Equals("KIT"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return MDService.ArticoloDelEnabled(currRec.CodArticolo);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cloning record
|
/// Cloning record
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="selRec"></param>
|
/// <param name="selRec"></param>
|
||||||
protected void cloneRecord(AnagArticoliModel selRec)
|
private void cloneRecord(AnagArticoliModel selRec)
|
||||||
{
|
{
|
||||||
isNewArt = true;
|
isNewArt = true;
|
||||||
// creo record duplicato...
|
// creo record duplicato...
|
||||||
@@ -105,7 +198,7 @@ namespace MP.SPEC.Pages
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="selRec"></param>
|
/// <param name="selRec"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected async Task deleteRecord(AnagArticoliModel selRec)
|
private async Task deleteRecord(AnagArticoliModel selRec)
|
||||||
{
|
{
|
||||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Eliminazione Articolo: sei sicuro di voler procedere?"))
|
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Eliminazione Articolo: sei sicuro di voler procedere?"))
|
||||||
return;
|
return;
|
||||||
@@ -116,138 +209,16 @@ namespace MP.SPEC.Pages
|
|||||||
await Task.Delay(1);
|
await Task.Delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ForceReload(int newNum)
|
private void ForceReload(int newNum)
|
||||||
{
|
{
|
||||||
numRecord = newNum;
|
numRecord = newNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ForceReloadPage(int newNum)
|
private void ForceReloadPage(int newNum)
|
||||||
{
|
{
|
||||||
currPage = newNum;
|
currPage = newNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
numRecord = 10;
|
|
||||||
await ReloadBaseData();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
|
||||||
{
|
|
||||||
await ReloadDataAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void ResetData()
|
|
||||||
{
|
|
||||||
isNewArt = false;
|
|
||||||
currRecord = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task ResetSearch()
|
|
||||||
{
|
|
||||||
SearchVal = "";
|
|
||||||
await ResetDataAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task resetSel()
|
|
||||||
{
|
|
||||||
isNewArt = false;
|
|
||||||
currRecord = null;
|
|
||||||
await Task.Delay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task selRecord(AnagArticoliModel selRec)
|
|
||||||
{
|
|
||||||
isNewArt = false;
|
|
||||||
currRecord = selRec;
|
|
||||||
await Task.Delay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task UpdateAsync(AnagArticoliModel selRec)
|
|
||||||
{
|
|
||||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Confermi di voler salvare le modifiche?"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var done = await MDService.ArticoliUpdateRecord(selRec);
|
|
||||||
await ResetDataAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task ResetDataAsync()
|
|
||||||
{
|
|
||||||
currPage = 1;
|
|
||||||
currRecord = null;
|
|
||||||
await ReloadDataAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Protected Methods
|
|
||||||
|
|
||||||
#region Private Fields
|
|
||||||
|
|
||||||
private string _selAzienda = "*";
|
|
||||||
private SelectArticoliParams currFilter = new SelectArticoliParams();
|
|
||||||
private AnagArticoliModel? currRecord = null;
|
|
||||||
private bool isNewArt = false;
|
|
||||||
private List<AnagGruppiModel>? ListAziende;
|
|
||||||
private List<AnagArticoliModel>? ListRecords;
|
|
||||||
private List<ListValuesModel>? ListTipoArt;
|
|
||||||
private int maxNumRecord = 1000;
|
|
||||||
private int availRecord = 1000;
|
|
||||||
private int totRecord = 0;
|
|
||||||
private List<AnagArticoliModel>? SearchRecords;
|
|
||||||
|
|
||||||
#endregion Private Fields
|
|
||||||
|
|
||||||
#region Private Properties
|
|
||||||
|
|
||||||
private int _currPage = 1;
|
|
||||||
private int _numRecord = 10;
|
|
||||||
|
|
||||||
private int currPage
|
|
||||||
{
|
|
||||||
get => _currPage;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_currPage != value)
|
|
||||||
{
|
|
||||||
_currPage = value;
|
|
||||||
UpdateTable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool isLoading { get; set; } = false;
|
|
||||||
|
|
||||||
private int numRecord
|
|
||||||
{
|
|
||||||
get => _numRecord;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_numRecord != value)
|
|
||||||
{
|
|
||||||
_numRecord = value;
|
|
||||||
UpdateTable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string searchVal { get; set; } = "";
|
|
||||||
|
|
||||||
private string selAzienda
|
|
||||||
{
|
|
||||||
get => _selAzienda;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value != _selAzienda)
|
|
||||||
{
|
|
||||||
_selAzienda = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Tipo articolo selezionato
|
|
||||||
/// </summary>
|
|
||||||
private string selTipoArt = "*";
|
|
||||||
|
|
||||||
private async Task ReloadAziendaAsync()
|
private async Task ReloadAziendaAsync()
|
||||||
{
|
{
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
@@ -263,28 +234,9 @@ namespace MP.SPEC.Pages
|
|||||||
await ResetDataAsync();
|
await ResetDataAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool ShowCharts { get; set; } = false;
|
|
||||||
|
|
||||||
#endregion Private Properties
|
|
||||||
|
|
||||||
#region Private Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Verifica cancellabilità record
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="selRec"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private bool ArticoloDelEnabled(AnagArticoliModel currRec)
|
|
||||||
{
|
|
||||||
if (currRec.Tipo.Equals("KIT"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return MDService.ArticoloDelEnabled(currRec.CodArticolo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ReloadBaseData()
|
private async Task ReloadBaseData()
|
||||||
{
|
{
|
||||||
|
isLoading = true;
|
||||||
await MDService.EnsureArtCacheLoadedAsync(true);
|
await MDService.EnsureArtCacheLoadedAsync(true);
|
||||||
selAzienda = await MDService.ConfigTryGetAsync("AZIENDA");
|
selAzienda = await MDService.ConfigTryGetAsync("AZIENDA");
|
||||||
if (string.IsNullOrEmpty(selAzienda))
|
if (string.IsNullOrEmpty(selAzienda))
|
||||||
@@ -295,11 +247,6 @@ namespace MP.SPEC.Pages
|
|||||||
ListTipoArt = await MDService.AnagTipoArtLvAsync();
|
ListTipoArt = await MDService.AnagTipoArtLvAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Verifica cablata x add tutto tranne KIT
|
|
||||||
/// </summary>
|
|
||||||
private bool CanAdd => !selTipoArt.Equals("KIT");
|
|
||||||
|
|
||||||
private async Task ReloadDataAsync()
|
private async Task ReloadDataAsync()
|
||||||
{
|
{
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
@@ -309,9 +256,55 @@ namespace MP.SPEC.Pages
|
|||||||
UpdateTable();
|
UpdateTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ResetData()
|
||||||
|
{
|
||||||
|
isNewArt = false;
|
||||||
|
currRecord = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ResetDataAsync()
|
||||||
|
{
|
||||||
|
currPage = 1;
|
||||||
|
currRecord = null;
|
||||||
|
await MDService.FlushFusionCacheArticoli();
|
||||||
|
await ReloadDataAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ResetSearch()
|
||||||
|
{
|
||||||
|
SearchVal = "";
|
||||||
|
await ResetDataAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ResetSel()
|
||||||
|
{
|
||||||
|
isNewArt = false;
|
||||||
|
currRecord = null;
|
||||||
|
await ResetDataAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task selRecord(AnagArticoliModel selRec)
|
||||||
|
{
|
||||||
|
isNewArt = false;
|
||||||
|
currRecord = selRec;
|
||||||
|
await Task.Delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateAsync(AnagArticoliModel selRec)
|
||||||
|
{
|
||||||
|
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Confermi di voler salvare le modifiche?"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var done = await MDService.ArticoliUpsertRecord(selRec);
|
||||||
|
await ResetDataAsync();
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateTable()
|
private void UpdateTable()
|
||||||
{
|
{
|
||||||
ListRecords = SearchRecords?.Skip(numRecord * (currPage - 1)).Take(numRecord).ToList() ?? new();
|
ListRecords = SearchRecords?
|
||||||
|
.Skip(numRecord * (currPage - 1))
|
||||||
|
.Take(numRecord)
|
||||||
|
.ToList() ?? new();
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
@page "/force-reset"
|
@page "/force-reset"
|
||||||
|
@page "/ForceReset"
|
||||||
@using MP.AppAuth.Services
|
@using MP.AppAuth.Services
|
||||||
@using MP.SPEC.Data
|
@using MP.SPEC.Data
|
||||||
|
|
||||||
@@ -47,6 +48,13 @@
|
|||||||
nextVal = 10;
|
nextVal = 10;
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
await Task.Delay(bDelay);
|
await Task.Delay(bDelay);
|
||||||
|
// svuoto cache redis...
|
||||||
|
ConfigModel updRec = new ConfigModel()
|
||||||
|
{
|
||||||
|
Chiave = "AZIENDA",
|
||||||
|
Valore = "*"
|
||||||
|
};
|
||||||
|
await MDService.ConfigUpdateAsync(updRec);
|
||||||
title = "UserDataReload...";
|
title = "UserDataReload...";
|
||||||
currVal = 50;
|
currVal = 50;
|
||||||
nextVal = 80;
|
nextVal = 80;
|
||||||
|
|||||||
@@ -68,8 +68,6 @@ else
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@*<div class="card-footer">
|
|
||||||
</div>*@
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,13 @@
|
|||||||
using Blazored.SessionStorage;
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.WebUtilities;
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
using MP.Data.DbModels;
|
using MP.Data.DbModels;
|
||||||
|
using MP.Data.Services;
|
||||||
using MP.SPEC.Data;
|
using MP.SPEC.Data;
|
||||||
|
|
||||||
namespace MP.SPEC.Pages
|
namespace MP.SPEC.Pages
|
||||||
{
|
{
|
||||||
public partial class Giacenze
|
public partial class Giacenze
|
||||||
{
|
{
|
||||||
#region Protected Fields
|
|
||||||
|
|
||||||
protected List<ODLModel>? elencoOdl;
|
|
||||||
|
|
||||||
#endregion Protected Fields
|
|
||||||
|
|
||||||
#region Protected Properties
|
|
||||||
|
|
||||||
protected int IdxOdl { get; set; } = 0;
|
|
||||||
|
|
||||||
protected ODLExpModel? odlExp { get; set; } = null!;
|
|
||||||
|
|
||||||
#endregion Protected Properties
|
|
||||||
|
|
||||||
#region Protected Methods
|
#region Protected Methods
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
@@ -41,34 +27,43 @@ namespace MP.SPEC.Pages
|
|||||||
odlExp = await MDService.OdlByKeyAsync(IdxOdl);
|
odlExp = await MDService.OdlByKeyAsync(IdxOdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void saveBatch(string newBatch)
|
||||||
|
{
|
||||||
|
BatchSel = newBatch;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Protected Methods
|
#endregion Protected Methods
|
||||||
|
|
||||||
|
#region Private Fields
|
||||||
|
|
||||||
|
private List<ODLModel>? elencoOdl;
|
||||||
|
|
||||||
|
private string giacenzeConf = "false";
|
||||||
|
|
||||||
|
#endregion Private Fields
|
||||||
|
|
||||||
#region Private Properties
|
#region Private Properties
|
||||||
|
|
||||||
|
private string BatchSel { get; set; } = "";
|
||||||
|
private int IdxOdl { get; set; } = 0;
|
||||||
|
|
||||||
|
private string mainTabCss
|
||||||
|
{
|
||||||
|
get => !string.IsNullOrEmpty(BatchSel) ? "col-10" : "col-12";
|
||||||
|
}
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private MpDataService MDService { get; set; } = null!;
|
private MpDataService MDService { get; set; } = null!;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private NavigationManager NavManager { get; set; } = null!;
|
private NavigationManager NavManager { get; set; } = null!;
|
||||||
|
|
||||||
|
private ODLExpModel? odlExp { get; set; } = null!;
|
||||||
private string padCodXdl { get; set; } = "00000";
|
private string padCodXdl { get; set; } = "00000";
|
||||||
private string giacenzeConf = "false";
|
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private ISessionStorageService sessionStorage { get; set; } = null!;
|
private ISessionStorageService sessionStorage { get; set; } = null!;
|
||||||
|
|
||||||
private string BatchSel { get; set; } = "";
|
|
||||||
|
|
||||||
private string mainTabCss
|
|
||||||
{
|
|
||||||
get => !string.IsNullOrEmpty(BatchSel) ? "col-10" : "col-12";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void saveBatch(string newBatch)
|
|
||||||
{
|
|
||||||
BatchSel = newBatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Private Properties
|
#endregion Private Properties
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-0 align-content-center d-flex justify-content-end">
|
<div class="px-0 align-content-center d-flex justify-content-end">
|
||||||
@* <small class="fs-5">Edit Massivo Fermi</small> *@
|
<div class="input-group">
|
||||||
|
<span class="input-group-text"><i class="fa fa-search"></i></span>
|
||||||
|
@if (ShowDetail)
|
||||||
|
{
|
||||||
|
<input type="text" class="form-control disabled" disabled placeholder="Search Ctr-R" @bind="@SearchVal" @bind:after="ReloadDataAsync" accesskey="R">
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input type="text" class="form-control" placeholder="Search Alt-R" @bind="@SearchVal" @bind:after="ReloadDataAsync" accesskey="R">
|
||||||
|
}
|
||||||
|
<button class="btn @btnSearchCss" @onclick="DoReset"><i class="fa fa-ban"></i></button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -24,7 +35,7 @@
|
|||||||
{
|
{
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="@cssMain">
|
<div class="@cssMain">
|
||||||
<ListOperatori CurrRecords="@ListOperatori" AllRecords="@ListOperatori" AddEnabled="false" DelEnabled="false" StaChgEnab="true" EC_RecSel="ShowDetail"></ListOperatori>
|
<ListOperatori CurrRecords="@ListOperatori" AllRecords="@ListOperatori" AddEnabled="false" DelEnabled="false" StaChgEnab="true" EC_RecSel="DoSelect"></ListOperatori>
|
||||||
</div>
|
</div>
|
||||||
@if (SelRec != null)
|
@if (SelRec != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,28 +26,31 @@ namespace MP.SPEC.Pages
|
|||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private bool isLoading = false;
|
private bool isLoading = false;
|
||||||
private List<AnagOperatoriModel> ListOperatori = new();
|
|
||||||
private List<RepartiDTO> ListGruppi = new();
|
private List<RepartiDTO> ListGruppi = new();
|
||||||
|
private List<AnagOperatoriModel> ListOperatori = new();
|
||||||
|
private string SearchVal = "";
|
||||||
private AnagOperatoriModel? SelRec = null;
|
private AnagOperatoriModel? SelRec = null;
|
||||||
|
|
||||||
#endregion Private Fields
|
#endregion Private Fields
|
||||||
|
|
||||||
#region Private Properties
|
#region Private Properties
|
||||||
|
|
||||||
|
private string btnSearchCss => string.IsNullOrWhiteSpace(SearchVal) ? "btn-secondary" : "btn-primary";
|
||||||
private string cssMain => SelRec == null ? "col-12" : "col-6";
|
private string cssMain => SelRec == null ? "col-12" : "col-6";
|
||||||
|
|
||||||
|
private bool ShowDetail => SelRec != null;
|
||||||
|
|
||||||
#endregion Private Properties
|
#endregion Private Properties
|
||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
private async Task ReloadDataAsync()
|
private async Task DoReset()
|
||||||
{
|
{
|
||||||
isLoading = true;
|
SearchVal = "";
|
||||||
ListOperatori = await MDService.OperatoriGetFiltAsync("*");
|
await ReloadDataAsync();
|
||||||
isLoading = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShowDetail(AnagOperatoriModel? newRec)
|
private async Task DoSelect(AnagOperatoriModel? newRec)
|
||||||
{
|
{
|
||||||
SelRec = newRec;
|
SelRec = newRec;
|
||||||
if (SelRec == null)
|
if (SelRec == null)
|
||||||
@@ -61,6 +64,22 @@ namespace MP.SPEC.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ReloadDataAsync()
|
||||||
|
{
|
||||||
|
isLoading = true;
|
||||||
|
var rawList = await MDService.OperatoriGetFiltAsync("*");
|
||||||
|
if (string.IsNullOrEmpty(SearchVal))
|
||||||
|
{
|
||||||
|
ListOperatori = rawList;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ListOperatori = rawList
|
||||||
|
.Where(x => x.Cognome.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase) || x.Nome.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase)).ToList();
|
||||||
|
}
|
||||||
|
isLoading = false;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Private Methods
|
#endregion Private Methods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,7 +224,7 @@ namespace MP.SPEC.Pages
|
|||||||
{
|
{
|
||||||
newParams.CurrPage = 1;
|
newParams.CurrPage = 1;
|
||||||
}
|
}
|
||||||
await InvokeAsync(() => StateHasChanged());
|
await InvokeAsync(StateHasChanged);
|
||||||
currFilter = newParams;
|
currFilter = newParams;
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-10
@@ -12,13 +12,13 @@
|
|||||||
<div class="input-group-text">
|
<div class="input-group-text">
|
||||||
<span class="me-1" title="Elenco PODL disponibili da produrre">Da Produrre</span>
|
<span class="me-1" title="Elenco PODL disponibili da produrre">Da Produrre</span>
|
||||||
<div class="form-check form-check-sm form-switch py-1" title="Modalità display (Disponibili / Lanciati)">
|
<div class="form-check form-check-sm form-switch py-1" title="Modalità display (Disponibili / Lanciati)">
|
||||||
<input class="form-check-input" type="checkbox" name="setupAlarms" @onclick="() => toggleClosed()">
|
<input class="form-check-input" type="checkbox" name="setupAlarms" @onclick="() => DoToggleClosed()">
|
||||||
</div>
|
</div>
|
||||||
<span class="" title="Elenco PODL già lanciati/prodotti">Lanciati</span>
|
<span class="" title="Elenco PODL già lanciati/prodotti">Lanciati</span>
|
||||||
</div>
|
</div>
|
||||||
@if (addEnabled)
|
@if (addEnabled)
|
||||||
{
|
{
|
||||||
<button class="btn btn-success" @onclick="() => reqNewPODL()">Nuovo PODL <i class="bi bi-plus-square"></i></button>
|
<button class="btn btn-success" @onclick="() => ReqNewPODL()">Nuovo PODL <i class="bi bi-plus-square"></i></button>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -29,6 +29,30 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="d-flex justify-content-end col-6">
|
<div class="d-flex justify-content-end col-6">
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
|
<div class="p-1">
|
||||||
|
<div class="input-group input-group-sm d-flex justify-content-between">
|
||||||
|
<div class="input-group-text" id="inputGroup-sizing-sm">
|
||||||
|
<div class="pe-3" title="PODL Kit Child">
|
||||||
|
Kit C
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-check-sm form-switch py-1" title="Mostra KIT">
|
||||||
|
<input class="form-check-input" type="checkbox" @bind="@ShowKit">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-1">
|
||||||
|
<div class="input-group input-group-sm d-flex justify-content-between">
|
||||||
|
<div class="input-group-text" id="inputGroup-sizing-sm">
|
||||||
|
<div class="pe-3" title="Attivabile">
|
||||||
|
Attivi
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-check-sm form-switch py-1" title="Mostra Solo Attivi">
|
||||||
|
<input class="form-check-input" type="checkbox" @bind="@OnlyAtt">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="p-1">
|
<div class="p-1">
|
||||||
<div class="input-group me-2" style="min-width: 20rem;">
|
<div class="input-group me-2" style="min-width: 20rem;">
|
||||||
<span class="input-group-text"><i class="fa fa-search"></i></span>
|
<span class="input-group-text"><i class="fa fa-search"></i></span>
|
||||||
@@ -41,15 +65,15 @@
|
|||||||
<div class=" rounded small d-flex justify-content-between" title="Filtri attivi">
|
<div class=" rounded small d-flex justify-content-between" title="Filtri attivi">
|
||||||
@if (selReparto != "*")
|
@if (selReparto != "*")
|
||||||
{
|
{
|
||||||
<button class="btn btn-outline-primary btn-sm mx-2" @onclick="() => resetReparto()" title="Rimuovi Filtro Reparto"><i class="fa-solid fa-building"></i>   <i class="fa-solid fa-xmark text-warning"></i></button>
|
<button class="btn btn-outline-primary btn-sm mx-2" @onclick="() => DoResetReparto()" title="Rimuovi Filtro Reparto"><i class="fa-solid fa-building"></i>   <i class="fa-solid fa-xmark text-warning"></i></button>
|
||||||
}
|
}
|
||||||
@if (macchina != "*")
|
@if (macchina != "*")
|
||||||
{
|
{
|
||||||
<button class="btn btn-outline-primary btn-sm mx-2" @onclick="() => resetMacchina()" title="Rimuovi Filtro Impianto"><i class="fa-solid fa-hard-drive"></i>   <i class="fa-solid fa-xmark text-warning"></i></button>
|
<button class="btn btn-outline-primary btn-sm mx-2" @onclick="() => DoResetMacchina()" title="Rimuovi Filtro Impianto"><i class="fa-solid fa-hard-drive"></i>   <i class="fa-solid fa-xmark text-warning"></i></button>
|
||||||
}
|
}
|
||||||
@if (StatoSel != "*")
|
@if (StatoSel != "*")
|
||||||
{
|
{
|
||||||
<button class="btn btn-outline-primary btn-sm mx-2" @onclick="() => resetFase()" title="Rimuovi Filtro Parametro"><i class="fa-solid fa-sliders"></i>   <i class="fa-solid fa-xmark text-warning"></i></button>
|
<button class="btn btn-outline-primary btn-sm mx-2" @onclick="() => DoResetFase()" title="Rimuovi Filtro Parametro"><i class="fa-solid fa-sliders"></i>   <i class="fa-solid fa-xmark text-warning"></i></button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -251,7 +275,7 @@
|
|||||||
{
|
{
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="d-grid gap-2">
|
<div class="d-grid gap-2">
|
||||||
<button class="btn btn-warning" @onclick="() => cancel()">Annulla <i class="bi bi-x-circle"></i></button>
|
<button class="btn btn-warning" @onclick="() => DoCancel()">Annulla <i class="bi bi-x-circle"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
@@ -259,7 +283,7 @@
|
|||||||
@* @if (currRecord.CodArticolo != "" && currRecord.CodFase != "" && selReparto != "*" && currRecord.IdxMacchina != "") *@
|
@* @if (currRecord.CodArticolo != "" && currRecord.CodFase != "" && selReparto != "*" && currRecord.IdxMacchina != "") *@
|
||||||
@if (canSaveEdit)
|
@if (canSaveEdit)
|
||||||
{
|
{
|
||||||
<button class="btn btn-success" @onclick="() => update(currRecord)">Salva <i class="bi bi-save"></i></button>
|
<button class="btn btn-success" @onclick="() => DoUpdate(currRecord)">Salva <i class="bi bi-save"></i></button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -268,14 +292,14 @@
|
|||||||
{
|
{
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="d-grid gap-2">
|
<div class="d-grid gap-2">
|
||||||
<button class="btn btn-warning" @onclick="() => cancel()">Chiudi <i class="bi bi-x-circle"></i></button>
|
<button class="btn btn-warning" @onclick="() => DoCancel()">Chiudi <i class="bi bi-x-circle"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="d-grid gap-2">
|
<div class="d-grid gap-2">
|
||||||
@if (enableForceSync)
|
@if (enableForceSync)
|
||||||
{
|
{
|
||||||
<button @onclick="() => forceSyncDb()" class="btn btn-success">Forza sync → macchina <i class="bi bi-fast-forward-circle"></i></button>
|
<button @onclick="() => DoForceSyncDb()" class="btn btn-success">Forza sync → macchina <i class="bi bi-fast-forward-circle"></i></button>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -301,7 +325,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ListPODL PagerResetReq="pgResetReq" RecordEdit="@editRecord" RecordSel="@selRecord" updateRecordCount="UpdateTotCount" actFilter="@currFilter" padCodXdl="@padCodXdl"></ListPODL>
|
<ListPODL PagerResetReq="DoResetReqPager" RecordEdit="@DoEditRecord" RecordSel="@DoSelRecord" updateRecordCount="UpdateTotCount" actFilter="@currFilter" padCodXdl="@padCodXdl"></ListPODL>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer py-1">
|
<div class="card-footer py-1">
|
||||||
|
|||||||
+236
-234
@@ -1,6 +1,7 @@
|
|||||||
#if false
|
#if false
|
||||||
using Blazored.LocalStorage;
|
using Blazored.LocalStorage;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using EgwCoreLib.Razor;
|
using EgwCoreLib.Razor;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
@@ -14,117 +15,11 @@ namespace MP.SPEC.Pages
|
|||||||
{
|
{
|
||||||
public partial class PODL
|
public partial class PODL
|
||||||
{
|
{
|
||||||
#region Protected Fields
|
|
||||||
|
|
||||||
protected bool enableForceSync = true;
|
|
||||||
protected bool enableStartPODL = true;
|
|
||||||
protected bool enableStopODL = true;
|
|
||||||
protected DataPager? pagerODL = null!;
|
|
||||||
|
|
||||||
protected bool reqNew = false;
|
|
||||||
|
|
||||||
#endregion Protected Fields
|
|
||||||
|
|
||||||
#region Protected Properties
|
|
||||||
|
|
||||||
protected string addMessage
|
|
||||||
{
|
|
||||||
get => addEnabled ? "" : "Manca Selezione Impianto / Fase";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool canSaveEdit
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
bool answ = false;
|
|
||||||
if (currRecord != null)
|
|
||||||
{
|
|
||||||
// controllo le condizioni di selezione fase
|
|
||||||
bool okSelReparto = (useFasi4KeyRich == "FASE" && selReparto != "*") || useFasi4KeyRich != "FASE";
|
|
||||||
// controllo condizione record valido
|
|
||||||
bool okCurrRecord = currRecord.CodArticolo != "" && currRecord.CodFase != "" && currRecord.IdxMacchina != "";
|
|
||||||
answ = okCurrRecord && okSelReparto;
|
|
||||||
}
|
|
||||||
return answ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected string header
|
|
||||||
{
|
|
||||||
get => currFilter.Header;
|
|
||||||
set => currFilter.Header = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
protected IJSRuntime JSRuntime { get; set; } = null!;
|
|
||||||
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
protected ILocalStorageService localStorage { get; set; } = null!;
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
protected MpDataService MDService { get; set; } = null!;
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
protected IOApiService MpIoApiCall { get; set; } = null!;
|
|
||||||
|
|
||||||
[Inject]
|
|
||||||
protected NavigationManager NavManager { get; set; } = null!;
|
|
||||||
|
|
||||||
protected string useFasi4KeyRich { get; set; } = "";
|
|
||||||
|
|
||||||
#endregion Protected Properties
|
|
||||||
|
|
||||||
#region Protected Methods
|
#region Protected Methods
|
||||||
|
|
||||||
protected async Task cancel()
|
|
||||||
{
|
|
||||||
currRecord = null;
|
|
||||||
await ReloadDataAsync();
|
|
||||||
await Task.Delay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task editRecord(PODLExpModel selRec)
|
|
||||||
{
|
|
||||||
canEdit = true;
|
|
||||||
// preseleziono ricerca articolo
|
|
||||||
if (selRec != null)
|
|
||||||
{
|
|
||||||
artSearch = selRec.CodArticolo.Length > nArtSearch ? selRec.CodArticolo.Substring(0, nArtSearch) : selRec.CodArticolo;
|
|
||||||
}
|
|
||||||
currRecord = selRec;
|
|
||||||
await Task.Delay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task forceSyncDb()
|
|
||||||
{
|
|
||||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Sei sicuro di voler (re)inviare i dati (Articoli, PODL) all'impianto?"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var clonedRec = MP.Data.Utils.POdlExt.convertToPOdl(currRecord);
|
|
||||||
await callSyncDb(clonedRec);
|
|
||||||
currRecord = null;
|
|
||||||
NavManager.NavigateTo(NavManager.Uri, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task getReparto()
|
|
||||||
{
|
|
||||||
string keyStor = "reparto";
|
|
||||||
string localReparto = await localStorage.GetItemAsync<string>(keyStor, "") ?? "";
|
|
||||||
if (!string.IsNullOrEmpty(localReparto))
|
|
||||||
{
|
|
||||||
selReparto = localReparto;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
selReparto = "*";
|
|
||||||
await localStorage.SetItemAsync(keyStor, selReparto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await getReparto();
|
await GetReparto();
|
||||||
ListAziende = await MDService.ElencoAziendeAsync();
|
ListAziende = await MDService.ElencoAziendeAsync();
|
||||||
var allGruppiData = await MDService.ElencoGruppiFaseAsync();
|
var allGruppiData = await MDService.ElencoGruppiFaseAsync();
|
||||||
if (allGruppiData != null)
|
if (allGruppiData != null)
|
||||||
@@ -164,132 +59,6 @@ namespace MP.SPEC.Pages
|
|||||||
await ReloadDataAsync();
|
await ReloadDataAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task pgResetReq(bool doReset)
|
|
||||||
{
|
|
||||||
if (doReset)
|
|
||||||
{
|
|
||||||
await Task.Delay(1);
|
|
||||||
if (pagerODL != null)
|
|
||||||
{
|
|
||||||
pagerODL.resetCurrPage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Crea nuovo record e va in editing...
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected async Task reqNewPODL()
|
|
||||||
{
|
|
||||||
canEdit = true;
|
|
||||||
header = "Nuovo PODL";
|
|
||||||
artSearch = "";
|
|
||||||
string codExt = $"{currFase}";
|
|
||||||
string codGruppo = "";
|
|
||||||
if (ListGruppiFase != null && ListGruppiFase.Count > 0)
|
|
||||||
{
|
|
||||||
var firstFase = ListGruppiFase.FirstOrDefault(x => x.CodGruppo.StartsWith(currAzienda));
|
|
||||||
if (firstFase != null)
|
|
||||||
{
|
|
||||||
codGruppo = firstFase.CodGruppo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string codMacc = "";
|
|
||||||
if (ListMacchine != null && ListMacchine.Count > 0)
|
|
||||||
{
|
|
||||||
var firstMacc = ListMacchine.FirstOrDefault(x => x.Nome.Contains(currAzienda));
|
|
||||||
if (firstMacc != null)
|
|
||||||
{
|
|
||||||
codMacc = firstMacc.IdxMacchina;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currRecord = new PODLExpModel()
|
|
||||||
{
|
|
||||||
CodArticolo = "",//currArticolo,
|
|
||||||
KeyBCode = codExt,
|
|
||||||
KeyRichiesta = codExt,
|
|
||||||
CodGruppo = codGruppo,
|
|
||||||
IdxMacchina = codMacc,
|
|
||||||
NumPezzi = 1,
|
|
||||||
DueDate = DateTime.Now.AddDays(30)
|
|
||||||
};
|
|
||||||
await Task.Delay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void resetFase()
|
|
||||||
{
|
|
||||||
StatoSel = "*";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void resetMacchina()
|
|
||||||
{
|
|
||||||
macchina = "*";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task resetReparto()
|
|
||||||
{
|
|
||||||
string keyStor = "reparto";
|
|
||||||
selReparto = "*";
|
|
||||||
await localStorage.SetItemAsync(keyStor, selReparto);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task selRecord(PODLExpModel selRec)
|
|
||||||
{
|
|
||||||
canEdit = false;
|
|
||||||
currRecord = selRec;
|
|
||||||
await Task.Delay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void SetNumRec(int newNum)
|
|
||||||
{
|
|
||||||
currPage = 1;
|
|
||||||
numRecord = newNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void SetPage(int newNum)
|
|
||||||
{
|
|
||||||
currPage = newNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task toggleClosed()
|
|
||||||
{
|
|
||||||
hasOdl = !hasOdl;
|
|
||||||
await Task.Delay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task update(PODLExpModel selRec)
|
|
||||||
{
|
|
||||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Confermi di voler salvare le modifiche?"))
|
|
||||||
return;
|
|
||||||
await Task.Delay(1);
|
|
||||||
var clonedRec = MP.Data.Utils.POdlExt.convertToPOdl(selRec);
|
|
||||||
// se x qualche motivo mancasse codGruppo --> sistemo!
|
|
||||||
if (string.IsNullOrEmpty(clonedRec.CodGruppo))
|
|
||||||
{
|
|
||||||
clonedRec.CodGruppo = currGruppoSel.CodGruppo;
|
|
||||||
Log.Error($"CodGruppo mancante: messo valore selezionato: {currGruppoSel.CodGruppo}");
|
|
||||||
}
|
|
||||||
// se selezionato sovrascrivo...
|
|
||||||
if (useFasi4KeyRich == "FASE")
|
|
||||||
{
|
|
||||||
clonedRec.CodGruppo = currGruppoSel.CodGruppo;
|
|
||||||
}
|
|
||||||
var done = await MDService.POdlUpdateRecord(clonedRec);
|
|
||||||
// se attivabile chiamo sync
|
|
||||||
if (clonedRec.Attivabile)
|
|
||||||
{
|
|
||||||
await callSyncDb(clonedRec);
|
|
||||||
}
|
|
||||||
currRecord = null;
|
|
||||||
NavManager.NavigateTo(NavManager.Uri, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void UpdateTotCount(int newTotCount)
|
|
||||||
{
|
|
||||||
totalCount = newTotCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Protected Methods
|
#endregion Protected Methods
|
||||||
|
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
@@ -298,12 +67,21 @@ namespace MP.SPEC.Pages
|
|||||||
private PODLExpModel? _currRecord = null;
|
private PODLExpModel? _currRecord = null;
|
||||||
private AnagGruppiModel currGruppoSel = new AnagGruppiModel();
|
private AnagGruppiModel currGruppoSel = new AnagGruppiModel();
|
||||||
private PODLExpModel currRecordControlli = new PODLExpModel();
|
private PODLExpModel currRecordControlli = new PODLExpModel();
|
||||||
|
private bool enableForceSync = true;
|
||||||
|
private bool enableStartPODL = true;
|
||||||
|
private bool enableStopODL = true;
|
||||||
private List<AnagArticoliModel>? ListArticoli;
|
private List<AnagArticoliModel>? ListArticoli;
|
||||||
private List<AnagGruppiModel>? ListAziende;
|
private List<AnagGruppiModel>? ListAziende;
|
||||||
private List<AnagGruppiModel>? ListGruppiFase;
|
private List<AnagGruppiModel>? ListGruppiFase;
|
||||||
private List<MacchineModel>? ListMacchine;
|
private List<MacchineModel>? ListMacchine;
|
||||||
private List<ListValuesModel>? ListStati;
|
private List<ListValuesModel>? ListStati;
|
||||||
private int nArtSearch = 5;
|
private int nArtSearch = 5;
|
||||||
|
private DataPager? pagerODL = null!;
|
||||||
|
#if false
|
||||||
|
private bool reqNew = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private string useFasi4KeyRich = "";
|
||||||
|
|
||||||
#endregion Private Fields
|
#endregion Private Fields
|
||||||
|
|
||||||
@@ -323,6 +101,11 @@ namespace MP.SPEC.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string addMessage
|
||||||
|
{
|
||||||
|
get => addEnabled ? "" : "Manca Selezione Impianto / Fase";
|
||||||
|
}
|
||||||
|
|
||||||
private string artSearch
|
private string artSearch
|
||||||
{
|
{
|
||||||
get => _artSearch;
|
get => _artSearch;
|
||||||
@@ -346,6 +129,23 @@ namespace MP.SPEC.Pages
|
|||||||
|
|
||||||
private bool canEdit { get; set; } = false;
|
private bool canEdit { get; set; } = false;
|
||||||
|
|
||||||
|
private bool canSaveEdit
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
bool answ = false;
|
||||||
|
if (currRecord != null)
|
||||||
|
{
|
||||||
|
// controllo le condizioni di selezione fase
|
||||||
|
bool okSelReparto = (useFasi4KeyRich == "FASE" && selReparto != "*") || useFasi4KeyRich != "FASE";
|
||||||
|
// controllo condizione record valido
|
||||||
|
bool okCurrRecord = currRecord.CodArticolo != "" && currRecord.CodFase != "" && currRecord.IdxMacchina != "";
|
||||||
|
answ = okCurrRecord && okSelReparto;
|
||||||
|
}
|
||||||
|
return answ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string currAzienda
|
private string currAzienda
|
||||||
{
|
{
|
||||||
get => _currAzienda;
|
get => _currAzienda;
|
||||||
@@ -407,20 +207,47 @@ namespace MP.SPEC.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string header
|
||||||
|
{
|
||||||
|
get => currFilter.Header;
|
||||||
|
set => currFilter.Header = value;
|
||||||
|
}
|
||||||
|
|
||||||
private bool isLoading { get; set; } = false;
|
private bool isLoading { get; set; } = false;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private IJSRuntime JSRuntime { get; set; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private ILocalStorageService localStorage { get; set; } = null!;
|
||||||
|
|
||||||
private string macchina
|
private string macchina
|
||||||
{
|
{
|
||||||
get => currFilter.IdxMacchina;
|
get => currFilter.IdxMacchina;
|
||||||
set => currFilter.IdxMacchina = value;
|
set => currFilter.IdxMacchina = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private MpDataService MDService { get; set; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private IOApiService MpIoApiCall { get; set; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private NavigationManager NavManager { get; set; } = null!;
|
||||||
|
|
||||||
private int numRecord
|
private int numRecord
|
||||||
{
|
{
|
||||||
get => currFilter.NumRec;
|
get => currFilter.NumRec;
|
||||||
set => currFilter.NumRec = value;
|
set => currFilter.NumRec = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool OnlyAtt
|
||||||
|
{
|
||||||
|
get => currFilter.IsActive;
|
||||||
|
set => currFilter.IsActive = value;
|
||||||
|
}
|
||||||
|
|
||||||
private string padCodXdl { get; set; } = "00000";
|
private string padCodXdl { get; set; } = "00000";
|
||||||
|
|
||||||
private DateTime selDtEnd
|
private DateTime selDtEnd
|
||||||
@@ -455,6 +282,14 @@ namespace MP.SPEC.Pages
|
|||||||
set => currFilter.CodReparto = value;
|
set => currFilter.CodReparto = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool ShowKit
|
||||||
|
{
|
||||||
|
get => currFilter.ShowKit;
|
||||||
|
set => currFilter.ShowKit = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string sSearchCss => string.IsNullOrEmpty(currFilter.SearchVal) ? "btn-secondary" : "btn-primary";
|
||||||
|
|
||||||
private string StatoSel
|
private string StatoSel
|
||||||
{
|
{
|
||||||
get => currFilter.CodFase;
|
get => currFilter.CodFase;
|
||||||
@@ -491,6 +326,118 @@ namespace MP.SPEC.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task DoCancel()
|
||||||
|
{
|
||||||
|
currRecord = null;
|
||||||
|
await ReloadDataAsync();
|
||||||
|
await Task.Delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoEditRecord(PODLExpModel selRec)
|
||||||
|
{
|
||||||
|
canEdit = true;
|
||||||
|
// preseleziono ricerca articolo
|
||||||
|
if (selRec != null)
|
||||||
|
{
|
||||||
|
artSearch = selRec.CodArticolo.Length > nArtSearch ? selRec.CodArticolo.Substring(0, nArtSearch) : selRec.CodArticolo;
|
||||||
|
}
|
||||||
|
currRecord = selRec;
|
||||||
|
await Task.Delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoForceSyncDb()
|
||||||
|
{
|
||||||
|
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Sei sicuro di voler (re)inviare i dati (Articoli, PODL) all'impianto?"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var clonedRec = MP.Data.Utils.POdlExt.convertToPOdl(currRecord);
|
||||||
|
await callSyncDb(clonedRec);
|
||||||
|
currRecord = null;
|
||||||
|
NavManager.NavigateTo(NavManager.Uri, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoResetFase()
|
||||||
|
{
|
||||||
|
StatoSel = "*";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoResetMacchina()
|
||||||
|
{
|
||||||
|
macchina = "*";
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoResetReparto()
|
||||||
|
{
|
||||||
|
string keyStor = "reparto";
|
||||||
|
selReparto = "*";
|
||||||
|
await localStorage.SetItemAsync(keyStor, selReparto);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoResetReqPager(bool doReset)
|
||||||
|
{
|
||||||
|
if (doReset)
|
||||||
|
{
|
||||||
|
if (pagerODL != null)
|
||||||
|
{
|
||||||
|
pagerODL.resetCurrPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoSelRecord(PODLExpModel selRec)
|
||||||
|
{
|
||||||
|
canEdit = false;
|
||||||
|
currRecord = selRec;
|
||||||
|
await Task.Delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoToggleClosed()
|
||||||
|
{
|
||||||
|
hasOdl = !hasOdl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoUpdate(PODLExpModel selRec)
|
||||||
|
{
|
||||||
|
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Confermi di voler salvare le modifiche?"))
|
||||||
|
return;
|
||||||
|
await Task.Delay(1);
|
||||||
|
var clonedRec = MP.Data.Utils.POdlExt.convertToPOdl(selRec);
|
||||||
|
// se x qualche motivo mancasse codGruppo --> sistemo!
|
||||||
|
if (string.IsNullOrEmpty(clonedRec.CodGruppo))
|
||||||
|
{
|
||||||
|
clonedRec.CodGruppo = currGruppoSel.CodGruppo;
|
||||||
|
Log.Error($"CodGruppo mancante: messo valore selezionato: {currGruppoSel.CodGruppo}");
|
||||||
|
}
|
||||||
|
// se selezionato sovrascrivo...
|
||||||
|
if (useFasi4KeyRich == "FASE")
|
||||||
|
{
|
||||||
|
clonedRec.CodGruppo = currGruppoSel.CodGruppo;
|
||||||
|
}
|
||||||
|
var done = await MDService.POdlUpdateRecord(clonedRec);
|
||||||
|
// se attivabile chiamo sync
|
||||||
|
if (clonedRec.Attivabile)
|
||||||
|
{
|
||||||
|
await callSyncDb(clonedRec);
|
||||||
|
}
|
||||||
|
currRecord = null;
|
||||||
|
NavManager.NavigateTo(NavManager.Uri, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetReparto()
|
||||||
|
{
|
||||||
|
string keyStor = "reparto";
|
||||||
|
string localReparto = await localStorage.GetItemAsync<string>(keyStor, "") ?? "";
|
||||||
|
if (!string.IsNullOrEmpty(localReparto))
|
||||||
|
{
|
||||||
|
selReparto = localReparto;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
selReparto = "*";
|
||||||
|
await localStorage.SetItemAsync(keyStor, selReparto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ReloadDataAsync()
|
private async Task ReloadDataAsync()
|
||||||
{
|
{
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
@@ -507,7 +454,46 @@ namespace MP.SPEC.Pages
|
|||||||
isLoading = false;
|
isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string sSearchCss => string.IsNullOrEmpty(currFilter.SearchVal) ? "btn-secondary" : "btn-primary";
|
/// <summary>
|
||||||
|
/// Crea nuovo record e va in editing...
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task ReqNewPODL()
|
||||||
|
{
|
||||||
|
canEdit = true;
|
||||||
|
header = "Nuovo PODL";
|
||||||
|
artSearch = "";
|
||||||
|
string codExt = $"{currFase}";
|
||||||
|
string codGruppo = "";
|
||||||
|
if (ListGruppiFase != null && ListGruppiFase.Count > 0)
|
||||||
|
{
|
||||||
|
var firstFase = ListGruppiFase.FirstOrDefault(x => x.CodGruppo.StartsWith(currAzienda));
|
||||||
|
if (firstFase != null)
|
||||||
|
{
|
||||||
|
codGruppo = firstFase.CodGruppo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string codMacc = "";
|
||||||
|
if (ListMacchine != null && ListMacchine.Count > 0)
|
||||||
|
{
|
||||||
|
var firstMacc = ListMacchine.FirstOrDefault(x => x.Nome.Contains(currAzienda));
|
||||||
|
if (firstMacc != null)
|
||||||
|
{
|
||||||
|
codMacc = firstMacc.IdxMacchina;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currRecord = new PODLExpModel()
|
||||||
|
{
|
||||||
|
CodArticolo = "",//currArticolo,
|
||||||
|
KeyBCode = codExt,
|
||||||
|
KeyRichiesta = codExt,
|
||||||
|
CodGruppo = codGruppo,
|
||||||
|
IdxMacchina = codMacc,
|
||||||
|
NumPezzi = 1,
|
||||||
|
DueDate = DateTime.Now.AddDays(30)
|
||||||
|
};
|
||||||
|
await Task.Delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ResetSearch()
|
private async Task ResetSearch()
|
||||||
{
|
{
|
||||||
@@ -515,6 +501,17 @@ namespace MP.SPEC.Pages
|
|||||||
await ReloadDataAsync();
|
await ReloadDataAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetNumRec(int newNum)
|
||||||
|
{
|
||||||
|
currPage = 1;
|
||||||
|
numRecord = newNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPage(int newNum)
|
||||||
|
{
|
||||||
|
currPage = newNum;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task UpdateFilter(SelectXdlParams newParams)
|
private async Task UpdateFilter(SelectXdlParams newParams)
|
||||||
{
|
{
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
@@ -529,6 +526,11 @@ namespace MP.SPEC.Pages
|
|||||||
isLoading = false;
|
isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateTotCount(int newTotCount)
|
||||||
|
{
|
||||||
|
totalCount = newTotCount;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Private Methods
|
#endregion Private Methods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
<MP.SPEC.Components.Reparti.ListMacchine CodGruppoCurr="@CodGruppo" AllRecords="ListMacchineAll" CurrRecords="ListMacchine" EC_RecChange="ForceReload"></MP.SPEC.Components.Reparti.ListMacchine>
|
<MP.SPEC.Components.Reparti.ListMacchine CodGruppoCurr="@CodGruppo" AllRecords="ListMacchineAll" CurrRecords="ListMacchine" EC_RecChange="ForceReload"></MP.SPEC.Components.Reparti.ListMacchine>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<MP.SPEC.Components.Reparti.ListOperatori CodGruppoCurr="@CodGruppo" AllRecords="ListOperatoriAll" CurrRecords="ListOperatori" EC_RecChange="ForceReload"></MP.SPEC.Components.Reparti.ListOperatori>
|
<MP.SPEC.Components.Reparti.ListOperatori CodGruppoCurr="@CodGruppo" AllRecords="ListOperatoriAll" CurrRecords="ListOperatori" EC_RecChange="ForceReload" SelEnabled="false"></MP.SPEC.Components.Reparti.ListOperatori>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -57,10 +57,7 @@ namespace MP.SPEC.Pages
|
|||||||
|
|
||||||
#region Private Properties
|
#region Private Properties
|
||||||
|
|
||||||
private string btnSearchCss
|
private string btnSearchCss => string.IsNullOrWhiteSpace(SearchVal) ? "btn-secondary" : "btn-primary";
|
||||||
{
|
|
||||||
get => string.IsNullOrWhiteSpace(SearchVal) ? "btn-secondary" : "btn-primary";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string CssMain => ShowDetail ? "col-4" : "col-12";
|
private string CssMain => ShowDetail ? "col-4" : "col-12";
|
||||||
|
|
||||||
@@ -89,11 +86,10 @@ namespace MP.SPEC.Pages
|
|||||||
private async Task ReloadDataAsync()
|
private async Task ReloadDataAsync()
|
||||||
{
|
{
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
//ListMacchine?.Clear();
|
if (string.IsNullOrEmpty(CodGruppo))
|
||||||
if (string.IsNullOrEmpty(CodGruppo) || true)
|
|
||||||
{
|
{
|
||||||
ListReparti?.Clear();
|
ListReparti?.Clear();
|
||||||
var rawList = await MDService.ElencoRepartiDtoAsync();
|
var rawList = await MDService.ElencoRepartiDtoAsync(true);
|
||||||
if (string.IsNullOrEmpty(SearchVal))
|
if (string.IsNullOrEmpty(SearchVal))
|
||||||
{
|
{
|
||||||
ListReparti = rawList;
|
ListReparti = rawList;
|
||||||
|
|||||||
@@ -192,21 +192,6 @@ builder.Services.TryAddScoped<MpDataService>();
|
|||||||
builder.Services.TryAddSingleton<IOApiService>();
|
builder.Services.TryAddSingleton<IOApiService>();
|
||||||
builder.Services.TryAddScoped<MsgServiceSpec>();
|
builder.Services.TryAddScoped<MsgServiceSpec>();
|
||||||
|
|
||||||
#if false
|
|
||||||
builder.Services.AddSingleton<AppAuthService>();
|
|
||||||
builder.Services.AddSingleton<ListSelectDataSrv>();
|
|
||||||
builder.Services.AddSingleton<SharedMemService>();
|
|
||||||
builder.Services.AddSingleton<TabDataService>();
|
|
||||||
builder.Services.AddSingleton<TabDataFeeder>();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if false
|
|
||||||
// aggiunta helper local/session storage service
|
|
||||||
builder.Services.AddScoped<ISessionStorageService, SessionStorageService>();
|
|
||||||
builder.Services.AddScoped<ILocalStorageService, LocalStorageService>();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
builder.Services.AddHttpClient();
|
builder.Services.AddHttpClient();
|
||||||
|
|
||||||
logger.Info("Aggiunti services");
|
logger.Info("Aggiunti services");
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# MP.SPEC
|
||||||
|
|
||||||
|
MAPO SPEC: WebApp / Sito in versione dotNetCore 8 per la gestione del MES MAPO in particolare per le gestioni SPECiali (ina ttesa di finire di migrare SITE e ADM).
|
||||||
|
|
||||||
|
Comprende funzionalità amministrative avanzate e funzionalità standard.
|
||||||
|
|
||||||
|
## Sezioni Principali
|
||||||
|
|
||||||
|
Sono gestiti
|
||||||
|
* Articoli
|
||||||
|
* Operatori
|
||||||
|
* Assegnazione Operatori/Macchine a reparti
|
||||||
|
* PODL (Promesse ODL) prima della produzione
|
||||||
|
* ODL (Ordini di lavoro) legate ad effettive attività di produzione
|
||||||
|
* Gestione speciale dei KIT
|
||||||
|
* Gestione Dossier (es caso Baglietto)
|
||||||
|
* Gestione Ricette (tramite dossier)
|
||||||
|
* Gestione Parametri macchina
|
||||||
|
* Gestione giacenze magazzino (ove gestite)
|
||||||
|
|
||||||
|
Ci sono anche alcune pagine speciali di admin (ad esempio FluxLogStatus, usata per deduplicare i dati di FluxLog)
|
||||||
|
|
||||||
|
## Architettura
|
||||||
|
|
||||||
|
### Livello Dati (MP.Data)
|
||||||
|
|
||||||
|
Il layer dati centralizzato in `MP.Data` fornisce:
|
||||||
|
|
||||||
|
- **8 Repository**: Anag, Production, Dossier, FluxLog, System, MpVoc, MpMon, MpLand
|
||||||
|
- **Cache FusionCache** (Memory + Redis + DB) con invalidazione per tag
|
||||||
|
- **DI Registrations** attraverso `DataServiceCollectionExtensions` (`AddSpecDataLayer`, `AddLandDataLayer`, etc.)
|
||||||
|
- **MpDataService** come servizio singleton centrale per accesso a DB, Redis, MongoDB
|
||||||
|
|
||||||
|
### Livello Applicazione (MP.SPEC)
|
||||||
|
|
||||||
|
- **MpDataService** (Scoped, singleton in Program.cs): service wrapper sul DAL con caching FusionCache
|
||||||
|
- **Componenti Blazor Server**: layout interattivo server-side con `AddInteractiveServerComponents()`
|
||||||
|
- **API Controllers**: RecipeController, RecipeArchiveController per operazioni ricette
|
||||||
|
- **Autenticazione**: Windows Authentication (Negotiate) con Autorizzazione Blazor Server
|
||||||
|
|
||||||
|
### Livello Infrastruttura
|
||||||
|
|
||||||
|
- **SQL Server**: 4 DbContext (MoonProContext, MoonPro_VocContext, MoonPro_FluxContext, MoonPro_STATSContext)
|
||||||
|
- **MongoDB**: storage ricette
|
||||||
|
- **Redis**: caching distribuito (FusionCache) + backplane
|
||||||
|
- **OpenTelemetry**: tracing su Uptrace (abilitabile via conf)
|
||||||
|
- **MessagePipe**: broadcasting messaggi real-time
|
||||||
|
|
||||||
|
## Refactoring Completati (Giugno 2026)
|
||||||
|
|
||||||
|
### Repository Pattern - Decomposizione MpSpecController
|
||||||
|
|
||||||
|
Il grande `MpSpecController/MpSpecRepository.cs` è stato scomposto in 8 repository specialistici:
|
||||||
|
|
||||||
|
| # | Repository | Interfaccia | Metodi | DbContext |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | **Anag** | `IAnagRepository` | 26 | `MoonProContext` |
|
||||||
|
| 2 | **Production** | `IProductionRepository` | 32 | `MoonProContext` |
|
||||||
|
| 3 | **Dossier** | `IDossierRepository` | 6 | `MoonPro_FluxContext` |
|
||||||
|
| 4 | **FluxLog** | `IFluxLogRepository` | 3 | `MoonPro_FluxContext` |
|
||||||
|
| 5 | **System** | `ISystemRepository` | 7 | `MoonProContext` + `MoonProAdminContext` |
|
||||||
|
| 6 | **MpVoc** | `IMpVocRepository` | 3 | `MoonPro_VocContext` |
|
||||||
|
| 7 | **MpMon** | `IMpMonRepository` | 4 | `MoonProContext` |
|
||||||
|
| 8 | **MpLand** | `IMpLandRepository` | 6 | `MoonProContext` |
|
||||||
|
|
||||||
|
Tutti i reference a `dbController.XXX()` nei servizi sono stati rimossi. I metodi originali rimangono nel file di repository come fallback documentato.
|
||||||
|
|
||||||
|
### Migrazione FusionCache
|
||||||
|
|
||||||
|
Tutti i metodi di lettura in `MpDataService.cs` sono stati migrati al pattern `GetOrFetchAsync<T>()`:
|
||||||
|
- **L1 MemoryCache**: 1/3 della scadenza totale
|
||||||
|
- **L2 Redis (Distributed)**: TTL configurabile
|
||||||
|
- **L3 Database**: fetch diretto dal DbContext
|
||||||
|
- **Invalidazione**: per tag (es. `Utils.redisArtList`, `Utils.redisOdlByKey`)
|
||||||
|
- **48+ metodi** migrati o confermati corretti
|
||||||
|
|
||||||
|
### Fix DI e Static State (MP.AppAuth)
|
||||||
|
|
||||||
|
Risolto il null reference error originario (`Cannot provide a value for property 'AAService' on type 'CmpTop'`):
|
||||||
|
|
||||||
|
- Rimpiazzati tutti i `static IConfiguration _configuration` con `readonly` istanza nei controllers
|
||||||
|
- `AppAuthService` ora riceve i controllers via constructor DI invece di crearli con `new()`
|
||||||
|
- Registrazioni DI centralizzate in `DataServiceCollectionExtensions.cs`
|
||||||
|
- Tutti i controllers e services mp.appauth registrati come Scoped
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
Tutte le 10 soluzioni compilano con successo (0 errori):
|
||||||
|
MP.SPEC, MP.Data, MP.Land, MP.MON, MP.TAB3, MP.Stats, MP.INVE, MP.IOC, MP.RIOC, MP.Prog, IobConf
|
||||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<i>Modulo MAPOSPEC </i>
|
<i>Modulo MAPOSPEC </i>
|
||||||
<h4>Versione: 8.16.2606.408</h4>
|
<h4>Versione: 8.16.2606.1218</h4>
|
||||||
<br /> Note di rilascio:
|
<br /> Note di rilascio:
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user