Ok gestione eliminazione KIT

This commit is contained in:
Samuele Locatelli
2026-05-30 09:58:24 +02:00
parent 26e8ca0370
commit 79024ddcac
9 changed files with 142 additions and 125 deletions
+47 -70
View File
@@ -1264,26 +1264,21 @@ namespace MP.Data.Controllers
/// Elimina record
/// </summary>
/// <param name="rec2del"></param>
public bool IstKitDelete(IstanzeKitModel rec2del)
public async Task<bool> IstKitDeleteAsync(IstanzeKitModel rec2del)
{
bool fatto = false;
using (var dbCtx = new MoonProContext(options))
{
var actRec = dbCtx
using var dbCtx = new MoonProContext(options);
var actRec = await dbCtx
.DbSetInstKit
.Where(x => x.KeyKit == rec2del.KeyKit && x.KeyExtOrd == rec2del.KeyExtOrd)
.FirstOrDefault();
// se ci fosse aggiorno...
if (actRec != null)
{
dbCtx
.DbSetInstKit
.Remove(actRec);
}
var res = dbCtx.SaveChanges();
fatto = res != 0;
.FirstOrDefaultAsync();
// se ci fosse aggiorno...
if (actRec != null)
{
dbCtx
.DbSetInstKit
.Remove(actRec);
}
return fatto;
return await dbCtx.SaveChangesAsync() > 0;
}
/// <summary>
@@ -1324,35 +1319,30 @@ namespace MP.Data.Controllers
/// Esegue upsert record
/// </summary>
/// <param name="editRec"></param>
public bool IstKitUpsert(IstanzeKitModel editRec)
public async Task<bool> IstKitUpsertAsync(IstanzeKitModel editRec)
{
bool fatto = false;
using (var dbCtx = new MoonProContext(options))
{
var actRec = dbCtx
using var dbCtx = new MoonProContext(options);
var actRec = await dbCtx
.DbSetInstKit
.Where(x => x.KeyKit == editRec.KeyKit && x.KeyExtOrd == editRec.KeyExtOrd)
.FirstOrDefault();
.FirstOrDefaultAsync();
// se ci fosse aggiorno...
if (actRec == null)
{
dbCtx
// se ci fosse aggiorno...
if (actRec == null)
{
await dbCtx
.DbSetInstKit
.Add(editRec);
}
else
{
actRec.CodArtParent = editRec.CodArtParent;
actRec.CodArtChild = editRec.CodArtChild;
actRec.QtyART = editRec.QtyART;
actRec.QtyKIT = editRec.QtyKIT;
dbCtx.Entry(actRec).State = EntityState.Modified;
}
var res = dbCtx.SaveChanges();
fatto = res != 0;
.AddAsync(editRec);
}
return fatto;
else
{
actRec.CodArtParent = editRec.CodArtParent;
actRec.CodArtChild = editRec.CodArtChild;
actRec.QtyART = editRec.QtyART;
actRec.QtyKIT = editRec.QtyKIT;
dbCtx.Entry(actRec).State = EntityState.Modified;
}
return await dbCtx.SaveChangesAsync() > 0;
}
/// <summary>
@@ -1468,22 +1458,17 @@ namespace MP.Data.Controllers
/// <param name="CodArticolo"></param>
/// <param name="OnlyAvail">True = aperti (=senza ODL)</param>
/// <returns></returns>
public List<PODLExpModel> ListPODL_ByCodArt(string CodArticolo, bool OnlyAvail)
public async Task<List<PODLExpModel>> ListPODL_ByCodArtAsync(string CodArticolo, bool OnlyAvail)
{
List<PODLExpModel> dbResult = new List<PODLExpModel>();
using (var dbCtx = new MoonProContext(options))
{
var pCodArticolo = new SqlParameter("@CodArticolo", CodArticolo);
var pOnlyAvail = new SqlParameter("@onlyAvail", OnlyAvail);
using var dbCtx = new MoonProContext(options);
var pCodArticolo = new SqlParameter("@CodArticolo", CodArticolo);
var pOnlyAvail = new SqlParameter("@onlyAvail", OnlyAvail);
dbResult = dbCtx
return await dbCtx
.DbSetPODLExp
.FromSqlRaw("EXEC stp_PODL_getByCodArt @CodArticolo, @onlyAvail", pCodArticolo, pOnlyAvail)
.AsNoTracking()
.ToList();
}
return dbResult;
.ToListAsync();
}
/// <summary>
@@ -1491,20 +1476,16 @@ namespace MP.Data.Controllers
/// </summary>
/// <param name="IdxPodlParent">IDX PODL parent</param>
/// <returns></returns>
public List<PODLExpModel> ListPODL_ByKitParent(int IdxPodlParent)
public async Task<List<PODLExpModel>> ListPODL_ByKitParentAsync(int IdxPodlParent)
{
List<PODLExpModel> dbResult = new List<PODLExpModel>();
using (var dbCtx = new MoonProContext(options))
{
var pIdxPodlParent = new SqlParameter("@IdxPodlParent", IdxPodlParent);
using var dbCtx = new MoonProContext(options);
var pIdxPodlParent = new SqlParameter("@IdxPodlParent", IdxPodlParent);
dbResult = dbCtx
return await dbCtx
.DbSetPODLExp
.FromSqlRaw("EXEC stp_PODL_getByParentKitIdx @IdxPodlParent", pIdxPodlParent)
.AsNoTracking()
.ToList();
}
return dbResult;
.ToListAsync();
}
/// <summary>
@@ -2369,19 +2350,15 @@ namespace MP.Data.Controllers
/// Effettua il task di eliminazione PODL KIT + istanze + riattivazione PODL originali disattivate tramite stored
/// </summary>
/// <param name="IdxPODL">IdxPODL parent</param>
public bool PodlIstKitDelete(int IdxPODL)
public async Task<bool> PodlIstKitDeleteAsync(int IdxPODL)
{
bool answ = false;
using (var dbCtx = new MoonProContext(options))
{
var pIdxPODL = new SqlParameter("@IdxPODL", IdxPODL);
using var dbCtx = new MoonProContext(options);
var pIdxPODL = new SqlParameter("@IdxPODL", IdxPODL);
var dbResult = dbCtx
.Database
.ExecuteSqlRaw("EXEC dbo.stp_PodlIstKit_delete @IdxPODL", pIdxPODL);
answ = dbResult != 0;
}
return answ;
var dbResult = await dbCtx
.Database
.ExecuteSqlRawAsync("EXEC dbo.stp_PodlIstKit_delete @IdxPODL", pIdxPODL);
return dbResult != 0;
}
/// <summary>
+1 -1
View File
@@ -156,7 +156,7 @@ namespace MP.SPEC.Components
if (recSel != null)
{
ListKitTemplate = await MDService.TemplateKitFiltAsync(recSel.CodArticolo, "");
ListPOdlKit = MDService.POdlListByKitParent(recSel.IdxPromessa);
ListPOdlKit = await MDService.POdlListByKitParentAsync(recSel.IdxPromessa);
}
else
{
@@ -101,8 +101,7 @@ namespace MP.SPEC.Components.ProdKit
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Eliminazione PODL + Istanze KIT: sei sicuro di voler procedere?"))
return;
// da provare...
var done = MDService.PodlIstKitDelete(selRec.IdxPromessa);
var done = await MDService.PodlIstKitDeleteAsync(selRec.IdxPromessa);
ReloadData();
await EC_ListUpdated.InvokeAsync(true);
}
@@ -301,7 +300,7 @@ namespace MP.SPEC.Components.ProdKit
{
isLoading = true;
// reset preliminare...
ListRecordsPODL = new List<PODLExpModel>();
ListRecordsPODL?.Clear();
var filtRecordsPODL = PodlRecords
.Where(x => !string.IsNullOrEmpty(x.KeyRichiesta) && x.KeyRichiesta.StartsWith("KIT"))
+22 -20
View File
@@ -1,6 +1,5 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using MP.Data;
using MP.Data.DbModels;
using MP.SPEC.Data;
using MP.SPEC.Services;
@@ -12,6 +11,9 @@ namespace MP.SPEC.Components.ProdKit
{
#region Public Properties
[Parameter]
public SelectXdlParams ActFilter { get; set; } = new SelectXdlParams();
[Parameter]
public EventCallback<PODLExpModel> EC_RecordSel { get; set; }
@@ -22,10 +24,11 @@ namespace MP.SPEC.Components.ProdKit
public EventCallback<bool> PagerResetReq { get; set; }
[Parameter]
public EventCallback<int> UpdateRecordCount { get; set; }
public List<PODLExpModel> AllRecords { get; set; } = null!;
private List<PODLExpModel> SelRecords = new();
[Parameter]
public SelectXdlParams ActFilter { get; set; } = new SelectXdlParams();
public EventCallback<int> UpdateRecordCount { get; set; }
#endregion Public Properties
@@ -49,7 +52,6 @@ namespace MP.SPEC.Components.ProdKit
public void Dispose()
{
currRecord = null;
SearchRecords = null;
ListRecords = null;
GC.Collect();
}
@@ -88,6 +90,11 @@ namespace MP.SPEC.Components.ProdKit
get => string.IsNullOrEmpty(SearchVal) ? "btn-secondary" : "btn-primary";
}
protected string sSearchtCss
{
get => string.IsNullOrEmpty(searchVal) ? "btn-secondary" : "btn-primary";
}
#endregion Protected Properties
#region Protected Methods
@@ -110,7 +117,7 @@ namespace MP.SPEC.Components.ProdKit
if (!lastFilter.Equals(ActFilter) || true)
{
lastFilter = ActFilter.clone();
await ReloadData();
await ReloadDataAsync();
}
}
@@ -124,15 +131,17 @@ namespace MP.SPEC.Components.ProdKit
});
}
protected async Task ReloadData()
protected async Task ReloadDataAsync()
{
ListRecords = null;
isLoading = true;
SearchRecords = await MDService.POdlToKitListGetFiltAsync(hasOdl, StatoSel, macchina, reparto, selDtStart, selDtEnd);
#if false
AllRecords = await MDService.POdlToKitListGetFiltAsync(hasOdl, StatoSel, macchina, reparto, selDtStart, selDtEnd);
#endif
// rivedere filtro FixMe ToDo!!!
// filtro tenendo SOLO se hanno keyRichiesta CodExt + ATTIVI + NON KIT | Hard Coded...
SearchRecords = SearchRecords
SelRecords = AllRecords
.Where(x => !string.IsNullOrEmpty(x.KeyRichiesta) && x.Attivabile && !x.KeyRichiesta.StartsWith("KIT"))
.ToList();
@@ -152,7 +161,7 @@ namespace MP.SPEC.Components.ProdKit
currPage = 1;
if (forceUpdate)
{
await ReloadData();
await ReloadDataAsync();
}
}
@@ -179,7 +188,7 @@ namespace MP.SPEC.Components.ProdKit
protected async Task UpdateData()
{
currRecord = null;
await ReloadData();
await ReloadDataAsync();
}
#endregion Protected Methods
@@ -197,15 +206,8 @@ namespace MP.SPEC.Components.ProdKit
/// </summary>
private List<string> odlCurrList = new List<string>();
private List<PODLExpModel>? SearchRecords;
private string searchVal = "";
protected string sSearchtCss
{
get => string.IsNullOrEmpty(searchVal) ? "btn-secondary" : "btn-primary";
}
#endregion Private Fields
#region Private Properties
@@ -298,9 +300,9 @@ namespace MP.SPEC.Components.ProdKit
private void UpdateTable()
{
totalCount = 0;
if (SearchRecords != null)
if (SelRecords != null)
{
var filtRec = new List<PODLExpModel>(SearchRecords);
var filtRec = new List<PODLExpModel>(SelRecords);
// se ho ricerca filtro!
if (!string.IsNullOrEmpty(searchVal))
{
@@ -310,7 +312,7 @@ namespace MP.SPEC.Components.ProdKit
{
int.TryParse(searchVal.Replace("PODL", ""), out idxPodl);
}
filtRec = SearchRecords
filtRec = AllRecords
.Where(x => (x.KeyRichiesta.Contains(searchVal, StringComparison.InvariantCultureIgnoreCase)
|| x.KeyBCode.Contains(searchVal, StringComparison.InvariantCultureIgnoreCase)
|| (x.IdxPromessa == idxPodl && idxPodl > 0))
+1 -1
View File
@@ -10,7 +10,7 @@
@if (DoAddNew)
{
<div class="col-6 mb-1 px-1">
<KitPodlMan PadCodXdl="@padCodXdl" EC_RecordSel="SavePodl" ActFilter="@ActFilt"></KitPodlMan>
<KitPodlMan AllRecords="@listPOdl2Kit" PadCodXdl="@padCodXdl" EC_RecordSel="SavePodl" ActFilter="@ActFilt"></KitPodlMan>
</div>
<div class="col-6 mb-1 px-1">
<KitComposer SearchRecords="@listWSM" KeyFilt="@keyFilt" EC_ListUpdated="ForceReloadData" EC_ListCleared="ForceReset"></KitComposer>
+3 -1
View File
@@ -129,6 +129,7 @@ namespace MP.SPEC.Components.ProdKit
private List<PODLExpModel> listPOdlCheck = new List<PODLExpModel>();
private List<TksScoreModel> listTSM = new List<TksScoreModel>();
private List<WipSetupKitModel> listWSM = new List<WipSetupKitModel>();
private List<PODLExpModel> listPOdl2Kit = new List<PODLExpModel>();
private string padCodXdl = "00000";
private string userName = "";
private string userNameFull = "";
@@ -187,6 +188,7 @@ namespace MP.SPEC.Components.ProdKit
{
listPOdlCheck = new List<PODLExpModel>();
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);
listWSM = await MDService.WipKitFiltAsync(keyFilt);
listTSM = await MDService.TksScoreAsync(keyFilt, 1000, true);
listIKP = await MDService.IstKitFiltAsync("", "");
@@ -199,7 +201,7 @@ namespace MP.SPEC.Components.ProdKit
// continuo con PODL
if (!string.IsNullOrEmpty(codArtKit))
{
listPOdlCheck = MDService.ListPODL_ByCodArt(codArtKit, true);
listPOdlCheck = await MDService.ListPODL_ByCodArtAsync(codArtKit, true);
}
isLoading = false;
}
+56 -25
View File
@@ -1150,20 +1150,28 @@ namespace MP.SPEC.Data
/// <param name="currRecord"></param>
public async Task<bool> IstKitDelete(IstanzeKitModel currRecord)
{
using var activity = ActivitySource.StartActivity("IstKitDelete");
string source = "DB+REDIS";
using var activity = ActivitySource.StartActivity("IstKitDeleteAsync");
string source = "DB";
bool fatto = false;
// salvo
fatto = dbController.IstKitDelete(currRecord);
fatto = await dbController.IstKitDeleteAsync(currRecord);
// svuoto cache
RedisValue pattern = $"{Utils.redisKitInst}:*";
await ExecFlushRedisPatternAsync(pattern);
await FlushKitCache();
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"IstKitDelete | Read from {source}: {activity?.Duration.TotalMilliseconds}ms");
LogTrace($"IstKitDeleteAsync | Read from {source}: {activity?.Duration.TotalMilliseconds}ms");
return fatto;
}
private async Task FlushKitCache()
{
#if false
RedisValue pattern = $"{Utils.redisKitInst}:*";
await ExecFlushRedisPatternAsync(pattern);
#endif
await FlushCacheByTagsAsync(new List<string>() { Utils.redisPOdlList, Utils.redisKitInst, Utils.redisKitWip, Utils.redisKitScore, Utils.redisPOdlByCodArt });
}
/// <summary>
/// Elenco Istanze KIT da ricerca
/// </summary>
@@ -1195,7 +1203,7 @@ namespace MP.SPEC.Data
// salvo
fatto = await dbController.IstKitInsertByWKSAsync(CodArtParent, KeyFilt);
// svuoto cache
await FlushCacheByTagAsync(Utils.redisPOdlList);
await FlushKitCache();
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"IstKitInsertByWKSAsync | {source} | {activity?.Duration.TotalMilliseconds}ms");
@@ -1208,17 +1216,16 @@ namespace MP.SPEC.Data
/// <param name="currRecord"></param>
public async Task<bool> IstKitUpsert(IstanzeKitModel currRecord)
{
using var activity = ActivitySource.StartActivity("IstKitUpsert");
string source = "DB+REDIS";
using var activity = ActivitySource.StartActivity("IstKitUpsertAsync");
string source = "DB";
bool fatto = false;
// salvo
fatto = dbController.IstKitUpsert(currRecord);
fatto = await dbController.IstKitUpsertAsync(currRecord);
// svuoto cache
RedisValue pattern = $"{Utils.redisKitInst}:*";
await ExecFlushRedisPatternAsync(pattern);
await FlushKitCache();
activity?.SetTag("data.source", source);
activity?.Stop();
LogTrace($"IstKitUpsert | {source} | {activity?.Duration.TotalMilliseconds}ms");
LogTrace($"IstKitUpsertAsync | {source} | {activity?.Duration.TotalMilliseconds}ms");
return fatto;
}
@@ -1245,15 +1252,24 @@ namespace MP.SPEC.Data
/// <param name="CodArticolo"></param>
/// <param name="OnlyAvail">True = aperti (=senza ODL)</param>
/// <returns></returns>
public List<PODLExpModel> ListPODL_ByCodArt(string CodArticolo, bool OnlyAvail)
public async Task<List<PODLExpModel>> ListPODL_ByCodArtAsync(string CodArticolo, bool OnlyAvail)
{
string avType = OnlyAvail ? "Avail" : "ALL";
string currKey = $"{Utils.redisPOdlByCodArt}:{CodArticolo}:{avType}";
return await GetOrFetchAsync(
operationName: "ListPODL_ByCodArtAsync",
cacheKey: currKey,
expiration: getRandTOut(redisLongTimeCache),
fetchFunc: async () => await dbController.ListPODL_ByCodArtAsync(CodArticolo, OnlyAvail) ?? new(),
tagList: [Utils.redisPOdlByCodArt]
);
#if false
List<PODLExpModel> result = new List<PODLExpModel>();
if (!string.IsNullOrEmpty(CodArticolo))
{
using var activity = ActivitySource.StartActivity("ListPODL_ByCodArt");
string source = "DB";
string avType = OnlyAvail ? "Avail" : "ALL";
string currKey = $"{Utils.redisPOdlByCodArt}:{CodArticolo}:{avType}";
// cerco in redis dato valore sel idxMaccSel...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue && rawData.Length() > 2)
@@ -1285,7 +1301,8 @@ namespace MP.SPEC.Data
{
Log.Debug("Errore CodArt vuoto");
}
return result;
return result;
#endif
}
/// <summary>
@@ -1757,19 +1774,22 @@ namespace MP.SPEC.Data
/// Effettua il task di eliminazione PODL KIT + istanze + riattivazione PODL originali disattivate tramite stored
/// </summary>
/// <param name="IdxPODL">IdxPODL parent</param>
public bool PodlIstKitDelete(int IdxPODL)
public async Task<bool> PodlIstKitDeleteAsync(int IdxPODL)
{
using var activity = ActivitySource.StartActivity("PodlIstKitDelete");
using var activity = ActivitySource.StartActivity("PodlIstKitDeleteAsync");
bool fatto = false;
// salvo
fatto = dbController.PodlIstKitDelete(IdxPODL);
fatto = await dbController.PodlIstKitDeleteAsync(IdxPODL);
// svuoto cache
await FlushCacheByTagsAsync(new List<string>() { Utils.redisPOdlList });
#if false
string pattern = $"{Utils.redisKit}:*";
if (!string.IsNullOrEmpty(pattern))
{
ExecFlushRedisPattern(pattern);
}
activity?.SetTag("data.source", "DB+REDIS");
}
#endif
activity?.SetTag("data.source", "DB");
return fatto;
}
@@ -1778,8 +1798,18 @@ namespace MP.SPEC.Data
/// </summary>
/// <param name="IdxPodlParent">IDX PODL parent</param>
/// <returns></returns>
public List<PODLExpModel> POdlListByKitParent(int IdxPodlParent)
public async Task<List<PODLExpModel>> POdlListByKitParentAsync(int IdxPodlParent)
{
string currKey = $"{Utils.redisPOdlList}_kit:ByParent:{IdxPodlParent}";
return await GetOrFetchAsync(
operationName: "POdlListByKitParentAsync",
cacheKey: currKey,
expiration: getRandTOut(redisShortTimeCache),
fetchFunc: async () => await dbController.ListPODL_ByKitParentAsync(IdxPodlParent) ?? new(),
tagList: [Utils.redisPOdlList]
);
#if false
using var activity = ActivitySource.StartActivity("POdlListByKitParent");
List<PODLExpModel>? result = new List<PODLExpModel>();
string source = "DB";
@@ -1793,7 +1823,7 @@ namespace MP.SPEC.Data
}
else
{
result = dbController.ListPODL_ByKitParent(IdxPodlParent);
result = await dbController.ListPODL_ByKitParentAsync(IdxPodlParent);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
@@ -1806,7 +1836,8 @@ namespace MP.SPEC.Data
activity?.SetTag("result.count", result.Count);
activity?.Stop();
LogTrace($"POdlListByKitParent | Read from {source}: {activity?.Duration.TotalMilliseconds}ms");
return result;
return result;
#endif
}
/// <summary>
+1 -1
View File
@@ -294,7 +294,7 @@ namespace MP.SPEC.Pages
get => doAddNew ? (isComposing ? "Completare o Resettare" : "Chiudi Composizione KIT") : "Composizione Nuovo KIT";
}
private SelectXdlParams currFilter { get; set; } = new SelectXdlParams();
private SelectXdlParams currFilter { get; set; } = new SelectXdlParams() { NumRec = 5 };
private int currPage
{
+9 -3
View File
@@ -19,7 +19,7 @@ Migrare la logica di caching manuale (Redis + DB) verso l'utilizzo di `IFusionCa
### Fase 2: Refactoring Metodi di Lettura (Cache-aside) (In corso)
#### ✅ Metodi Migrati (Usano già `GetOrFetchAsync` o `FusionCache.GetOrSet`)
#### ✅ Metodi Migrati (Usano già `GetOrFetchAsync`, `FusionCache.GetOrSet` o `FlushCacheByTagAsync`)
- `AnagEventiGeneralAsync`
- `AnagStatiCommAsync`
- `AnagTipoArtLvAsync`
@@ -46,7 +46,7 @@ Migrare la logica di caching manuale (Redis + DB) verso l'utilizzo di `IFusionCa
- `OdlListGetFiltAsync`
- `OperatoriGetFiltAsync`
- `ParametriGetFiltAsync`
- `PODL_getDictOdlPodlAsync` (Migrato con gestione manuale L1/L2)
- `PODL_getDictOdlPodlAsync` (Gestione manuale L1/L2 con FusionCache)
- `POdlGetByOdlAsync`
- `POdlToKitListGetFiltAsync`
- `StatoMacchinaAsync`
@@ -59,11 +59,16 @@ Migrare la logica di caching manuale (Redis + DB) verso l'utilizzo di `IFusionCa
- `TemplateKitUpsertAsync` (Migrato con tag invalidazione)
- `WipKitDeleteAsync` (Migrato con tag invalidazione)
- `WipKitUpsertAsync` (Migrato con tag invalidazione)
- `AnagGruppiDeleteAsync` (Migrato con tag invalidazione)
- `AnagGruppiUpsertAsync` (Migrato con tag invalidazione)
- `Grp2MaccDeleteAsync` (Migrato con tag invalidazione)
- `Grp2MaccInsertAsync` (Migrato con tag invalidazione)
- `Grp2OperDeleteAsync` (Migrato con tag invalidazione)
- `Grp2OperInsertAsync` (Migrato con tag invalidazione)
#### 🛠️ Metodi da Migrare (Usano ancora Redis/DB manuale)
- [ ] Migrazione di `ActionGetReq` (linea 110: usa `redisDb.StringGetAsync`).
- [ ] Migrazione di `ActionSetReq` (linea 136: usa `BroadastMsgPipe.saveAndSendMessage`).
- [ ] Migrazione di `AnagGruppiDelete`/`Upsert` (linea 189/208: usa `ExecFlushRedisPattern`).
- [ ] Migrazione di `ArticoliDeleteRecord`/`UpdateRecord` (linea 296/372: usa `resetCacheArticoli`).
- [ ] Migrazione di `DbDedupStats` (linea 516: usa `redisDb.StringGet`).
- [ ] Migrazione di `DossiersDeleteRecord` (linea 554: usa `ExecFlushRedisPatternAsync`).
@@ -88,3 +93,4 @@ Migrare la logica di caching manuale (Redis + DB) verso l'utilizzo di `IFusionCa