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 /// /// Verifica offerte scadute, con update sul DB /// public async Task 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; }); } /// /// Esegue il cloning completo di un Offer e di TUTTE le relative righe... /// /// /// public async Task 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; }); } /// /// Reset cache sistema x Offerte modalità async /// public async Task 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; }); } /// /// Elenco completo Offer da DB /// /// public async Task> 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 ); }); } /// /// /// public async Task 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 ); }); } /// /// Elenco completo Offer da DB /// /// public async Task> 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 ); }); } /// /// Effettua update dei costi di tutte le righe del Offer indicato /// /// /// public async Task 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>(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; }); } /// /// Upsert record Offer /// /// /// public async Task 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 } }