Da testare ma completato porting OrderRows

This commit is contained in:
Samuele Locatelli
2026-03-17 19:17:49 +01:00
parent a6f42b827e
commit ea228a9691
11 changed files with 430 additions and 28 deletions
@@ -404,7 +404,6 @@ namespace EgwCoreLib.Lux.Data.Controllers
return dbResult;
}
/// Elimina riga e sposta eventuali righe successive...
/// </summary>
/// <param name="rec2Del"></param>
@@ -29,7 +29,7 @@ namespace EgwCoreLib.Lux.Data.Repository.Sales
Task<bool> UpdateAsync(OfferModel entity);
Task<bool> UpdateCostAsync(int OfferID);
Task<bool> UpdateCostAsync(int offerId);
#endregion Public Methods
}
@@ -1,4 +1,5 @@
using EgwCoreLib.Lux.Data.DbModel.Sales;
using EgwCoreLib.Lux.Data.DbModel.Items;
using EgwCoreLib.Lux.Data.DbModel.Sales;
namespace EgwCoreLib.Lux.Data.Repository.Sales
{
@@ -10,17 +11,20 @@ namespace EgwCoreLib.Lux.Data.Repository.Sales
Task<bool> DeleteAsync(OfferRowModel entity);
Task<OfferRowModel?> GetByUidAsync(string offerRowUid);
Task<List<ItemModel>> GetBomItemsAsync();
Task<OfferRowModel?> GetByIdAsync(int offerRowId);
Task<List<OfferRowModel>> GetByParentAsync(int offerId);
Task<OfferRowModel?> GetByUidAsync(string offerRowUid);
Task<List<ItemGroupModel>> GetItemGroupsAsync();
Task<bool> SaveRowsAsync(List<OfferRowModel> rows);
Task<bool> UpdateAsync(OfferRowModel entity);
#endregion Public Methods
}
}
}
@@ -1,5 +1,7 @@
using EgwCoreLib.Lux.Data.DbModel.Sales;
using EgwCoreLib.Lux.Data.DbModel.Items;
using EgwCoreLib.Lux.Data.DbModel.Sales;
using Microsoft.EntityFrameworkCore;
using static EgwCoreLib.Lux.Core.Enums;
namespace EgwCoreLib.Lux.Data.Repository.Sales
{
@@ -22,7 +24,6 @@ namespace EgwCoreLib.Lux.Data.Repository.Sales
return await dbCtx.SaveChangesAsync() > 0;
}
public async Task<bool> DeleteAsync(OfferRowModel entity)
{
await using var dbCtx = await CreateContextAsync();
@@ -30,13 +31,12 @@ namespace EgwCoreLib.Lux.Data.Repository.Sales
return await dbCtx.SaveChangesAsync() > 0;
}
public async Task<OfferRowModel?> GetByUidAsync(string offerRowUid)
public async Task<List<ItemModel>> GetBomItemsAsync()
{
await using var dbCtx = await CreateContextAsync();
return await dbCtx.DbSetOfferRow
.Include(r => r.SellingItemNav)
.FirstOrDefaultAsync(x => x.OfferRowUID == offerRowUid);
return await dbCtx.DbSetItem
.Where(x => x.ItemType == ItemClassType.Bom || x.ItemType == ItemClassType.BomAlt)
.ToListAsync();
}
public async Task<OfferRowModel?> GetByIdAsync(int offerRowId)
@@ -47,7 +47,6 @@ namespace EgwCoreLib.Lux.Data.Repository.Sales
.FirstOrDefaultAsync(x => x.OfferRowID == offerRowId);
}
public async Task<List<OfferRowModel>> GetByParentAsync(int offerId)
{
await using var dbCtx = await CreateContextAsync();
@@ -57,6 +56,20 @@ namespace EgwCoreLib.Lux.Data.Repository.Sales
.ToListAsync();
}
public async Task<OfferRowModel?> GetByUidAsync(string offerRowUid)
{
await using var dbCtx = await CreateContextAsync();
return await dbCtx.DbSetOfferRow
.Include(r => r.SellingItemNav)
.FirstOrDefaultAsync(x => x.OfferRowUID == offerRowUid);
}
public async Task<List<ItemGroupModel>> GetItemGroupsAsync()
{
await using var dbCtx = await CreateContextAsync();
return await dbCtx.DbSetItemGroup.ToListAsync();
}
public async Task<bool> SaveRowsAsync(List<OfferRowModel> rows)
{
await using var dbCtx = await CreateContextAsync();
@@ -86,4 +99,4 @@ namespace EgwCoreLib.Lux.Data.Repository.Sales
#endregion Public Methods
}
}
}
@@ -1,4 +1,5 @@
using EgwCoreLib.Lux.Data.DbModel.Sales;
using EgwCoreLib.Lux.Core.RestPayload;
using EgwCoreLib.Lux.Data.DbModel.Sales;
namespace EgwCoreLib.Lux.Data.Services.Sales
{
@@ -6,21 +7,25 @@ namespace EgwCoreLib.Lux.Data.Services.Sales
{
#region Public Methods
Task<bool> CloneAsync(OfferRowModel rec2clone);
Task<bool> DeleteAsync(OfferRowModel model);
Task<List<string>> FixRowUidAsync(int OfferId);
Task<List<string>> FixUidAsync(int offerId);
Task<List<OfferRowModel>> GetAllAsync();
Task<bool> FixImgTypeAsync(int offerId);
Task<List<OfferRowModel>> GetByParentAsync(int OfferId);
Task<OfferRowModel?> GetByUidAsync(string offerRowUid);
Task<bool> UpdateAwaitStateAsync(int OfferRowId, bool? awaitBom, bool? awaitPrice, bool flushCache = false);
Task<OfferRowModel?> GetByIdAsync(int offerRowId);
Task<List<OfferRowModel>> GetByParentAsync(int offerId);
Task<bool> UpdateAwaitStateAsync(int offerRowId, bool? awaitBom, bool? awaitPrice, bool flushCache = false);
Task<bool> UpdateBomAsync(int OfferRowID, List<BomItemDTO> newBomList);
Task<bool> UpdateFileDataAsync(OfferRowModel updRec);
Task<bool> UpdateSerStructAsync(int OfferRowID, string serStruct);
Task<bool> UpdateSerStructAsync(int offerRowID, string serStruct);
Task<bool> UpsertAsync(OfferRowModel upsRec);
@@ -0,0 +1,381 @@
using EgwCoreLib.Lux.Core.RestPayload;
using EgwCoreLib.Lux.Data.DbModel.Sales;
using EgwCoreLib.Lux.Data.Domains;
using EgwCoreLib.Lux.Data.Repository.Sales;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using StackExchange.Redis;
using static EgwCoreLib.Lux.Core.Enums;
namespace EgwCoreLib.Lux.Data.Services.Sales
{
public class OfferRowService : BaseServ, IOfferRowService
{
#region Public Constructors
public OfferRowService(
IConfiguration config,
IConnectionMultiplexer redis,
IOfferRowRepository repo) : base(config, redis)
{
_className = "OfferRow";
_repo = repo;
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Eliminazione record
/// </summary>
/// <param name="rec2del"></param>
/// <returns></returns>
public async Task<bool> DeleteAsync(OfferRowModel rec2del)
{
return await TraceAsync($"{_className}.Delete", async (activity) =>
{
var dbResult = await _repo.GetByIdAsync(rec2del.OfferRowID);
if (dbResult == null) return false;
bool success = await _repo.DeleteAsync(dbResult);
if (success)
{
await ClearCacheAsync($"{_redisBaseKey}:Offer:*");
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
}
return success;
});
}
/// <summary>
/// Effettua fix UID righe child del temoplate indicato e restituisce elenco UID da chiamare x refresh
/// </summary>
/// <param name="offerId">Key</param>
/// <returns></returns>
public async Task<List<string>> FixUidAsync(int offerId)
{
return await TraceAsync($"{_className}.FixUid", async (activity) =>
{
List<string> result = new List<string>();
// 1. Recupero righe
var rows = await _repo.GetByParentAsync(offerId);
if (rows == null)
return result;
// 2. Trovo quelle da sistemare
var list2fix = rows
.Where(x => string.IsNullOrEmpty(x.OfferRowUID) || x.OfferRowUID != x.OfferRowDtx)
.ToList();
// 3. Se non c’è nulla da fare → ritorno
if (list2fix.Count == 0)
return result;
// 4. Preparo la lista da restituire
result = list2fix
.Select(x => x.OfferRowDtx)
.ToList() ?? new List<string>();
// 5. Aggiorno i record
foreach (var row in list2fix)
row.OfferRowUID = row.OfferRowDtx;
// 6. Salvo
bool success = await _repo.SaveRowsAsync(list2fix);
if (success)
{
await ClearCacheAsync($"{_redisBaseKey}:Offer:*");
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
}
return result;
});
}
/// <summary>
/// Effettua fix TipoImg righe child dell' Offer indicato
/// </summary>
/// <param name="offerId">Key</param>
/// <returns></returns>
public async Task<bool> FixImgTypeAsync(int offerId)
{
return await TraceAsync($"{_className}.FixImgType", async (activity) =>
{
// 1. Recupero righe
var rows = await _repo.GetByParentAsync(offerId);
if (rows == null) return false;
// 2. Trovo quelle da sistemare
var list2fix = rows
.Where(x => x.ImgType == ImageType.ND)
.ToList();
// 3. Se non c’è nulla da fare → ritorno
if (list2fix.Count == 0)
return false;
// 5. Aggiorno i record
foreach (var row in list2fix)
{
// se è calcolato il selling item --> img calcolata
if (row.SellingItemNav != null && (row.SellingItemNav.SourceType == ItemSourceType.Jwd || row.SellingItemNav.SourceType == ItemSourceType.FileBTL))
{
row.ImgType = ImageType.Calculated;
}
}
// 6. Salvo
bool success = await _repo.SaveRowsAsync(list2fix);
if (success)
{
await ClearCacheAsync($"{_redisBaseKey}:Offer:*");
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
}
return true;
});
}
public async Task<OfferRowModel?> GetByUidAsync(string offerRowUid)
{
return await TraceAsync($"{_className}.GetByUid", async (activity) =>
{
return await GetOrSetCacheAsync(
$"{_redisBaseKey}:{_className}:ByUid:{offerRowUid}",
async () => await _repo.GetByUidAsync(offerRowUid),
LongCache
);
});
}
public async Task<OfferRowModel?> GetByIdAsync(int offerRowId)
{
return await TraceAsync($"{_className}.GetById", async (activity) =>
{
return await GetOrSetCacheAsync(
$"{_redisBaseKey}:{_className}:ById:{offerRowId}",
async () => await _repo.GetByIdAsync(offerRowId),
LongCache
);
});
}
/// <summary>
/// Elenco filtrato (parent) OfferRow da DB
/// </summary>
/// <param name="offerId"></param>
/// <returns></returns>
public async Task<List<OfferRowModel>> GetByParentAsync(int offerId)
{
return await TraceAsync($"{_className}.GetByParent", async (activity) =>
{
return await GetOrSetCacheAsync(
$"{_redisBaseKey}:{_className}:ByParent:{offerId}",
async () => await _repo.GetByParentAsync(offerId),
LongCache
);
});
}
public async Task<bool> UpdateAwaitStateAsync(int OfferRowId, bool? awaitBom, bool? awaitPrice, bool flushCache = false)
{
return await TraceAsync($"{_className}.UpdateAwaitState", async (activity) =>
{
var currRec = await _repo.GetByIdAsync(OfferRowId);
if (currRec == null)
return false;
//modalità vecchia
//if (awaitBom.HasValue)
// currRec.AwaitBom = awaitBom.Value;
//if (awaitPrice.HasValue)
// currRec.AwaitPrice = awaitPrice.Value;
currRec.AwaitBom = awaitBom ?? currRec.AwaitBom;
currRec.AwaitPrice = awaitPrice ?? currRec.AwaitPrice;
activity?.SetTag("db.operation", "UPDATE");
bool success = await _repo.UpdateAsync(currRec);
if (success && flushCache)
{
await ClearCacheAsync($"{_redisBaseKey}:Offer:*");
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
}
return success;
});
}
/// <summary>
/// Effettua update delle info legate al file per il Offer indicato
/// </summary>
/// <param name="updRec">Riga Offer coi dati da aggiornare</param>
/// <returns></returns>
public async Task<bool> UpdateFileDataAsync(OfferRowModel updRec)
{
return await TraceAsync($"{_className}.UpdateFileData", async (activity) =>
{
var currRec = await _repo.GetByIdAsync(updRec.OfferRowID);
if (currRec == null)
return false;
currRec.FileName = updRec.FileName;
currRec.FileResource = updRec.FileResource;
currRec.FileSize = updRec.FileSize;
currRec.SerStruct = updRec.SerStruct;
activity?.SetTag("db.operation", "UPDATE");
bool success = await _repo.UpdateAsync(currRec);
if (success)
{
await ClearCacheAsync($"{_redisBaseKey}:Offer:*");
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
}
return success;
});
}
/// <summary>
/// Effettua update del valore serializzato della Riga Offer
/// </summary>
/// <param name="OfferRowID">ID Riga Offer da aggiornare</param>
/// <param name="serStruct">Serializzazione oggetto (es JWD)</param>
/// <returns></returns>
public async Task<bool> UpdateBomAsync(int OfferRowID, List<BomItemDTO> newBomList)
{
return await TraceAsync($"{_className}.UpdateBom", async (activity) =>
{
var currRec = await _repo.GetByIdAsync(OfferRowID);
if (currRec == null)
return false;
var itemGroups = await _repo.GetItemGroupsAsync();
var bomItems = await _repo.GetBomItemsAsync();
// calcolo il NUOVO costo e lo aggiorno...
double totCost = 0;
double totPrice = 0;
int totItemQty = 0;
int numGroupOk = 0;
int numItemOk = 0;
int numElems = newBomList.Count;
// validazione e completamento BOM
BomCalculator.Validate(itemGroups, bomItems, ref newBomList, null, ref totCost, ref totPrice, ref totItemQty, ref numGroupOk, ref numItemOk);
// salvo BOM...
string itemBom = JsonConvert.SerializeObject(newBomList);
currRec.ItemBOM = itemBom;
// salvo arrotondato alla 3° decimale
currRec.BomCost = Math.Round(totCost, 3);
currRec.BomPrice = Math.Round(totPrice, 3);
currRec.BomOk = numElems == numGroupOk;
currRec.ItemOk = numElems == numItemOk;
currRec.ProdItemQty = totItemQty;
activity?.SetTag("db.operation", "UPDATE");
bool success = await _repo.UpdateAsync(currRec);
if (success)
{
await ClearCacheAsync($"{_redisBaseKey}:Offer:*");
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
}
return success;
});
}
/// <summary>
/// Effettua update del valore serializzato della Riga Offer
/// </summary>
/// <param name="OfferRowID">ID Riga Offer da aggiornare</param>
/// <param name="serStruct">Serializzazione oggetto (es JWD)</param>
/// <returns></returns>
public async Task<bool> UpdateSerStructAsync(int OfferRowID, string serStruct)
{
return await TraceAsync($"{_className}.UpdateSerStruct", async (activity) =>
{
var currRec = await _repo.GetByIdAsync(OfferRowID);
if (currRec == null)
return false;
currRec.SerStruct = serStruct;
activity?.SetTag("db.operation", "UPDATE");
bool success = await _repo.UpdateAsync(currRec);
if (success)
{
await ClearCacheAsync($"{_redisBaseKey}:Offer:*");
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
}
return success;
});
}
/// <summary>
/// Upsert record OfferRow
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
public async Task<bool> UpsertAsync(OfferRowModel upsRec)
{
return await TraceAsync($"{_className}.Upsert", async (activity) =>
{
var currRec = await _repo.GetByIdAsync(upsRec.OfferRowID);
string operation = "UPDATE";
bool success = false;
if (currRec != null)
{
success = await _repo.UpdateAsync(upsRec);
}
else
{
operation = "INSERT";
success = await _repo.AddAsync(upsRec);
}
activity?.SetTag("db.operation", operation);
if (success)
{
await ClearCacheAsync($"{_redisBaseKey}:Offer:*");
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
}
return success;
});
}
#endregion Public Methods
#region Private Fields
private readonly string _className;
private readonly IOfferRowRepository _repo;
#endregion Private Fields
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>1.1.2603.1718</Version>
<Version>1.1.2603.1719</Version>
</PropertyGroup>
<ItemGroup>
+1 -1
View File
@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspnet-Lux.UI-a758c101-a2f4-4e38-977d-1c4887dbbd50</UserSecretsId>
<Version>1.1.2603.1718</Version>
<Version>1.1.2603.1719</Version>
</PropertyGroup>
<ItemGroup>
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>LUX - Web Windows MES</i>
<h4>Versione: 1.1.2603.1718</h4>
<h4>Versione: 1.1.2603.1719</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
1.1.2603.1718
1.1.2603.1719
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.1.2603.1718</version>
<version>1.1.2603.1719</version>
<url>http://nexus.steamware.net/repository/SWS/GPW/stable/GPW.UI.zip</url>
<changelog>http://nexus.steamware.net/repository/SWS/GPW/stable/ChangeLog.html</changelog>
<mandatory>false</mandatory>