485 lines
18 KiB
C#
485 lines
18 KiB
C#
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 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);
|
|
|
|
// 2. Trovo quelle da sistemare
|
|
var list2fix = rows
|
|
.Where(x => x.ImgType == ImageType.ND)
|
|
.ToList();
|
|
|
|
// 3. Se non c'è nulla da fare → ritorno (nessun cambio necessario)
|
|
if (list2fix.Count == 0)
|
|
return true;
|
|
|
|
// 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;
|
|
});
|
|
}
|
|
|
|
/// <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) =>
|
|
{
|
|
var rows = await _repo.GetByParentAsync(offerId);
|
|
|
|
// 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 new List<string>();
|
|
|
|
// 4. Preparo la lista da restituire
|
|
var result = list2fix
|
|
.Select(x => x.OfferRowDtx)
|
|
.ToList();
|
|
|
|
// 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;
|
|
});
|
|
}
|
|
|
|
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<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<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;
|
|
|
|
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 della BOM (esplicita) della Riga Offer
|
|
/// </summary>
|
|
/// <param name="OfferRowID">ID Riga Offer da aggiornare</param>
|
|
/// <param name="newBomList">BOM List esplicita</param>
|
|
/// <returns></returns>
|
|
public async Task<bool> UpdateBomAsync(int OfferRowID, List<BomItemDTO> newBomList)
|
|
{
|
|
return await TraceAsync($"{_className}.UpdateBomById", 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", "UpdateBomById");
|
|
|
|
bool success = await _repo.UpdateAsync(currRec);
|
|
|
|
if (success)
|
|
{
|
|
await ClearCacheAsync($"{_redisBaseKey}:Offer:*");
|
|
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
|
}
|
|
|
|
return success;
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua update della BOM (esplicita) della Riga Offer
|
|
/// </summary>
|
|
/// <param name="uID">UID Riga Offer da aggiornare</param>
|
|
/// <param name="newBomList">BOM List esplicita</param>
|
|
/// <returns></returns>
|
|
public async Task<bool> UpdateBomAsync(string uID, List<BomItemDTO> newBomList)
|
|
{
|
|
return await TraceAsync($"{_className}.UpdateBomByUid", async (activity) =>
|
|
{
|
|
var currRec = await _repo.GetByUidAsync(uID);
|
|
if (currRec == null)
|
|
return false;
|
|
|
|
var itemGroups = await _repo.GetItemGroupsAsync();
|
|
var bomItems = await _repo.GetBomItemsAsync();
|
|
// recupero la BOM list precedente
|
|
var bomListPrev = JsonConvert.DeserializeObject<List<BomItemDTO>>(currRec.ItemBOM);
|
|
|
|
// 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, bomListPrev, 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;
|
|
// setto ok await di BOM e Price
|
|
currRec.AwaitBom = false;
|
|
currRec.AwaitPrice = false;
|
|
currRec.ProdItemQty = totItemQty;
|
|
|
|
activity?.SetTag("db.operation", "UpdateBomByUid");
|
|
|
|
bool success = await _repo.UpdateAsync(currRec);
|
|
|
|
if (success)
|
|
{
|
|
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;
|
|
currRec.ImgType = Core.Enums.ImageType.Calculated;
|
|
|
|
activity?.SetTag("db.operation", "UPDATE");
|
|
|
|
bool success = await _repo.UpdateAsync(currRec);
|
|
|
|
if (success)
|
|
{
|
|
await ClearCacheAsync($"{_redisBaseKey}:Offer:*");
|
|
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
|
}
|
|
|
|
return success;
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// <inheritdoc />
|
|
/// </summary>
|
|
public async Task<bool> UpdatePendReqAsync(int OfferRowID, Dictionary<string, string> reqDict)
|
|
{
|
|
return await TraceAsync($"{_className}.UpdatePendReqAsync", async (activity) =>
|
|
{
|
|
var currRec = await _repo.GetByIdAsync(OfferRowID);
|
|
|
|
if (currRec == null)
|
|
return false;
|
|
|
|
currRec.DictPendPresRaw = JsonConvert.SerializeObject(reqDict);
|
|
|
|
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;
|
|
currRec.ImgType = Core.Enums.ImageType.Calculated;
|
|
|
|
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 + dizionario richieste ancora da applicare (stato dirty)
|
|
/// </summary>
|
|
/// <param name="offerRowID">ID Riga Offer da aggiornare</param>
|
|
/// <param name="serStruct">Serializzazione oggetto (es JWD)</param>
|
|
/// <param name="reqDict">Dizionario richieste da salvare x review manuale</param>
|
|
/// <returns></returns>
|
|
public async Task<bool> UpdateSerStructDirtyAsync(int OfferRowID, string serStruct, Dictionary<string, string> reqDict)
|
|
{
|
|
return await TraceAsync($"{_className}.UpdateSerStructDirty", async (activity) =>
|
|
{
|
|
var currRec = await _repo.GetByIdAsync(OfferRowID);
|
|
|
|
if (currRec == null)
|
|
return false;
|
|
|
|
currRec.SerStruct = serStruct;
|
|
currRec.ImgType = Core.Enums.ImageType.Calculated;
|
|
currRec.DictPendPresRaw = JsonConvert.SerializeObject(reqDict);
|
|
|
|
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<OfferRowModel?> UpsertAsync(OfferRowModel upsRec)
|
|
{
|
|
return await TraceAsync($"{_className}.Upsert", async (activity) =>
|
|
{
|
|
OfferRowModel? 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);
|
|
|
|
if (!success) return null; // Return null on insert failure
|
|
}
|
|
|
|
activity?.SetTag("db.operation", operation);
|
|
|
|
if (success)
|
|
{
|
|
// sistemo UID...
|
|
await FixUidAsync(upsRec.OfferID);
|
|
await FixImgTypeAsync(upsRec.OfferID);
|
|
currRec = await _repo.GetByIdAsync(upsRec.OfferRowID);
|
|
}
|
|
else
|
|
{
|
|
// svuoto comunque cache...
|
|
await ClearCacheAsync($"{_redisBaseKey}:Offer:*");
|
|
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
|
}
|
|
|
|
return currRec;
|
|
});
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Private Fields
|
|
|
|
private readonly string _className;
|
|
private readonly IOfferRowRepository _repo;
|
|
|
|
#endregion Private Fields
|
|
}
|
|
} |