Files
lux/EgwCoreLib.Lux.Data/Services/Sales/OfferService.cs
T
2026-05-29 19:21:45 +02:00

237 lines
7.9 KiB
C#

namespace EgwCoreLib.Lux.Data.Services.Sales
{
public class OfferService : BaseServ, IOfferService
{
#region Public Constructors
public OfferService(
IConfiguration config,
IConnectionMultiplexer redis,
IOfferRepository repo) : base(config, redis)
{
_className = "Offer";
_repo = repo;
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Verifica offerte scadute, con update sul DB
/// </summary>
public async Task<bool> CheckExpiredAsync()
{
return await TraceAsync($"{_className}.CheckExpired", async (activity) =>
{
// eseguo clone
var result = await _repo.CheckExpiredAsync();
// se eseguito, pulisco la cache correlata
if (result)
{
await FlushCacheOffersAsync();
}
return result;
});
}
/// <summary>
/// Esegue il cloning completo di un Offer e di TUTTE le relative righe...
/// </summary>
/// <param name="rec2clone"></param>
/// <returns></returns>
public async Task<bool> CloneAsync(OfferModel rec2clone)
{
return await TraceAsync($"{_className}.Clone", async (activity) =>
{
// eseguo clone
var result = await _repo.CloneAsync(rec2clone);
// se eseguito, pulisco la cache correlata
if (result)
{
await FlushCacheOffersAsync();
}
return result;
});
}
/// <summary>
/// Reset cache sistema x Offerte modalità async
/// </summary>
public async Task<bool> FlushCacheOffersAsync()
{
return await TraceAsync($"{_className}.FlushCache", async (activity) =>
{
string operation = "FlushCache";
activity?.SetTag("db.operation", operation);
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
await ClearCacheAsync($"{_redisBaseKey}:OfferRows:*");
//await ClearCacheAsync($"{_redisBaseKey}:Offers:*");
return true;
});
}
/// <summary>
/// Elenco completo Offer da DB
/// </summary>
/// <returns></returns>
public async Task<List<OfferModel>> GetAllAsync()
{
// Uso helper TraceAsync che gestisce automaticamente StartActivity, Log e Exception tracking
return await TraceAsync($"{_className}.GetAllAsync", async (activity) =>
{
return await GetOrSetCacheAsync(
$"{_redisBaseKey}:{_className}:ALL",
async () => await _repo.GetAllAsync(),
LongCache
);
});
}
/// <summary>
/// <inheritdoc />
/// </summary>
public async Task<OfferModel?> GetByIdAsync(int OfferID)
{
// Uso helper TraceAsync che gestisce automaticamente StartActivity, Log e Exception tracking
return await TraceAsync($"{_className}.GetFilt", async (activity) =>
{
return await GetOrSetCacheAsync(
$"{_redisBaseKey}:{_className}:ById:{OfferID}",
async () => await _repo.GetByIdAsync(OfferID),
LongCache
);
});
}
/// <summary>
/// Elenco completo Offer da DB
/// </summary>
/// <returns></returns>
public async Task<List<OfferModel>> GetFiltAsync(DateTime inizio, DateTime fine)
{
// Uso helper TraceAsync che gestisce automaticamente StartActivity, Log e Exception tracking
return await TraceAsync($"{_className}.GetFilt", async (activity) =>
{
return await GetOrSetCacheAsync(
$"{_redisBaseKey}:{_className}:Filt:{inizio:yyMMdd-HHmm}:{fine:yyMMdd-HHmm}",
async () => await _repo.GetFiltAsync(inizio, fine),
LongCache
);
});
}
/// <summary>
/// Effettua update dei costi di tutte le righe del Offer indicato
/// </summary>
/// <param name="OfferId"></param>
/// <returns></returns>
public async Task<bool> UpdateCostAsync(int OfferId)
{
return await TraceAsync($"{_className}.UpdateCost", async (activity) =>
{
// 1. Recupero dati
var rows = await _repo.GetRowsAsync(OfferId);
if (rows.Count == 0)
return false;
var itemGroups = await _repo.GetItemGroupsAsync();
var bomItems = await _repo.GetBomItemsAsync();
// 2. Calcolo costi BOM
foreach (var row in rows)
{
if (!string.IsNullOrEmpty(row.ItemBOM) && row.ItemBOM.Length > 2)
{
var bomList = JsonConvert.DeserializeObject<List<BomItemDTO>>(row.ItemBOM);
if (bomList != null)
{
double totCost = 0;
double totPrice = 0;
int totItemQty = 0;
int numGroupOk = 0;
int numItemOk = 0;
BomCalculator.Validate(
itemGroups,
bomItems,
ref bomList,
null,
ref totCost,
ref totPrice,
ref totItemQty,
ref numGroupOk,
ref numItemOk
);
row.ItemBOM = JsonConvert.SerializeObject(bomList);
row.BomCost = Math.Round(totCost, 3);
row.BomPrice = Math.Round(totPrice, 3);
row.BomOk = bomList.Count == numGroupOk;
row.ItemOk = bomList.Count == numItemOk;
row.ProdItemQty = totItemQty;
}
}
}
// 3. Salvo
var result = await _repo.SaveRowsAsync(rows);
if (result)
{
// 4. Invalido cache
await FlushCacheOffersAsync();
}
return result;
});
}
/// <summary>
/// Upsert record Offer
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
public async Task<bool> UpsertAsync(OfferModel upsRec)
{
return await TraceAsync($"{_className}.Upsert", async (activity) =>
{
var currRec = await _repo.GetByIdAsync(upsRec.OfferID);
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 FlushCacheOffersAsync();
}
return success;
});
}
#endregion Public Methods
#region Private Fields
private readonly string _className;
private readonly IOfferRepository _repo;
#endregion Private Fields
}
}