Files
lux/EgwCoreLib.Lux.Data/Repository/Sales/OrderRepository.cs
T
2026-03-23 17:17:31 +01:00

350 lines
14 KiB
C#

using EgwCoreLib.Lux.Core.RestPayload;
using EgwCoreLib.Lux.Data.DbModel.Items;
using EgwCoreLib.Lux.Data.DbModel.Production;
using EgwCoreLib.Lux.Data.DbModel.Sales;
using EgwCoreLib.Lux.Data.Domains;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using static EgwCoreLib.Lux.Core.Enums;
namespace EgwCoreLib.Lux.Data.Repository.Sales
{
public class OrderRepository : BaseRepository, IOrderRepository
{
#region Public Constructors
public OrderRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
{
}
#endregion Public Constructors
#region Public Methods
public async Task<bool> AddAsync(OrderModel entity)
{
await using var dbCtx = await CreateContextAsync();
await dbCtx.DbSetOrder.AddAsync(entity);
return await dbCtx.SaveChangesAsync() > 0;
}
/// <summary>
/// Esegue il cloning completo di un Offerta e di TUTTE le relative righe...
/// </summary>
/// <param name="rec2clone"></param>
/// <returns></returns>
public async Task<OrderModel?> CloneOfferAsync(OfferModel rec2clone)
{
OrderModel? newRec = null;
await using var dbCtx = await CreateContextAsync();
// avvio transazione
await using var tx = await dbCtx.Database.BeginTransactionAsync();
try
{
DateTime now = DateTime.Now;
var currRec = await dbCtx.DbSetOffer
.Include(x => x.OfferRowNav)
.FirstOrDefaultAsync(x => x.OfferID == rec2clone.OfferID);
if (currRec == null)
return null;
DateTime adesso = DateTime.Now;
var lastRec = dbCtx
.DbSetOrder
.Where(x => x.RefYear == adesso.Year)
.OrderByDescending(x => x.RefNum)
.FirstOrDefault();
int newRefNum = lastRec != null ? lastRec.RefNum + 1 : 1;
// 2. Creo il nuovo parent
newRec = new OrderModel()
{
ConsNote = rec2clone.ConsNote,
CustomerID = rec2clone.CustomerID,
DealerID = rec2clone.DealerID,
Description = rec2clone.Description,
DictPresel = rec2clone.DictPresel,
Discount = rec2clone.Discount,
DueDateProm = rec2clone.DueDateProm,
DueDateReq = rec2clone.DueDateReq,
Envir = rec2clone.Envir,
Inserted = adesso,
Modified = adesso,
OfferID = rec2clone.OfferID,
OrderState = OrderStates.Created,
RefNum = newRefNum,
RefRev = 1,
RefYear = adesso.Year,
ValidUntil = currRec.ValidUntil
};
// 3. Clono i child
// sistemo child...
newRec.OrderRowNav = currRec.OfferRowNav
.Select(c => new OrderRowModel()
{
AwaitBom = c.AwaitBom,
AwaitPrice = c.AwaitPrice,
BomCost = c.BomCost,
BomOk = c.BomOk,
BomPrice = c.BomPrice,
Envir = c.Envir,
FileName = c.FileName,
FileResource = c.FileResource,
FileSize = c.FileSize,
Inserted = adesso,
ItemBOM = c.ItemBOM,
ItemJCD = c.ItemJCD,
ItemOk = c.ItemOk,
ItemSteps = c.ItemSteps,
ItemTags = c.ItemTags,
JobID = c.JobID,
Modified = adesso,
Note = c.Note,
ProdItemQty = c.ProdItemQty,
Qty = c.Qty,
RowNum = c.RowNum,
SellingItemID = c.SellingItemID,
SerStruct = c.SerStruct,
StepCost = c.StepCost,
StepFlowTime = c.StepFlowTime,
StepLeadTime = c.StepLeadTime,
StepPrice = c.StepPrice
})
.ToList();
// 4. Aggiungo il nuovo parent (EF aggiunge anche i child)
dbCtx.DbSetOrder.Add(newRec);
// 5. Salvo tutto
var numSave = await dbCtx.SaveChangesAsync();
// se ok sistemo UID...
if (numSave > 0 && newRec != null)
{
// sistemo UID...
foreach (var item in newRec.OrderRowNav)
{
item.OrderRowUID = item.OrderRowCode;
// alternativa da valutare..
if (false)
{
// genero tanti record collegati alla riga d'ordine...
for (int i = 0; i < item.ProdItemQtyTot; i++)
{
var child = new ProductionItemModel
{
OrderRowID = item.OrderRowID,
//OrderRowNav = item,
ItemCode = i + 1,
ExtItemCode = $"{item.OrderRowCode}-{i + 1:000}",
ProdBatchID = null
};
// aggiungo record
item.ProdItemNav.Add(child);
}
}
else
{
item.ProdItemNav = Enumerable.Range(1, (int)item.ProdItemQtyTot)
.Select(i => new ProductionItemModel
{
//OrderRowID = item.OrderRowID,
OrderRowNav = item,
ItemCode = i,
ExtItemCode = $"{item.OrderRowCode}-{i:000}",
ProdBatchID = null,
ProdItemTag = null //nullo e POI verrà sistemato
})
.ToList();
}
dbCtx.Entry(item).State = EntityState.Modified;
}
// salvo ulteriori variazioni
await dbCtx.SaveChangesAsync();
// tutti gli ordini e anno corrente...
await dbCtx.Database.ExecuteSqlRawAsync("CALL stp_ProdItem_UpdateProdItemTag(0,0);");
// committo in un unica transazione (da provare!!!)
await tx.CommitAsync();
}
}
catch
{
await tx.RollbackAsync();
throw;
}
return newRec;
}
public async Task<bool> DeleteAsync(OrderModel entity)
{
await using var dbCtx = await CreateContextAsync();
dbCtx.DbSetOrder.Remove(entity);
return await dbCtx.SaveChangesAsync() > 0;
}
public async Task<List<OrderModel>> GetAllAsync()
{
await using var dbCtx = await CreateContextAsync();
return await dbCtx.DbSetOrder
.Include(c => c.CustomerNav)
.Include(d => d.DealerNav)
.Include(o => o.OrderRowNav)
.AsNoTracking()
.ToListAsync();
}
public async Task<List<ItemModel>> GetBomItemsAsync()
{
await using var dbCtx = await CreateContextAsync();
return await dbCtx.DbSetItem
.Where(x => x.ItemType == ItemClassType.Bom || x.ItemType == ItemClassType.BomAlt)
.ToListAsync();
}
public async Task<OrderModel?> GetByIdAsync(int recId)
{
await using var dbCtx = await CreateContextAsync();
return await dbCtx.DbSetOrder.FirstOrDefaultAsync(x => x.OrderID == recId);
}
public async Task<List<OrderModel>> GetFiltAsync(DateTime inizio, DateTime fine)
{
await using var dbCtx = await CreateContextAsync();
return await dbCtx.DbSetOrder
.Where(x => x.Inserted >= inizio && x.Inserted <= fine)
.Include(c => c.CustomerNav)
.Include(d => d.DealerNav)
.Include(o => o.OrderRowNav)
.AsNoTracking()
.ToListAsync();
}
public async Task<List<ItemGroupModel>> GetItemGroupsAsync()
{
await using var dbCtx = await CreateContextAsync();
return await dbCtx.DbSetItemGroup.ToListAsync();
}
public async Task<List<OrderRowModel>> GetRowsAsync(int recId)
{
await using var dbCtx = await CreateContextAsync();
return await dbCtx.DbSetOrderRow
.Where(x => x.OrderID == recId)
.ToListAsync();
}
public async Task<bool> SaveRowsAsync(List<OrderRowModel> rows)
{
// Add validation for null or empty list
if (rows == null || rows.Count == 0) return false;
await using var dbCtx = await CreateContextAsync();
// Wrap in transaction for atomicity (batch update multiple rows)
await using var tx = await dbCtx.Database.BeginTransactionAsync();
try
{
foreach (var row in rows)
dbCtx.Entry(row).State = EntityState.Modified;
bool done = await dbCtx.SaveChangesAsync() > 0;
if (done)
tx.Commit();
return done;
}
catch
{
tx.Rollback();
throw;
}
}
public async Task<bool> UpdateAsync(OrderModel entity)
{
await using var dbCtx = await CreateContextAsync();
// Recuperiamo l'entità tracciata dal context
var trackedEntity = await dbCtx.DbSetOrder.FirstOrDefaultAsync(x => x.OrderID == entity.OrderID);
if (trackedEntity != null)
{
// Aggiorna i valori dell'entità tracciata con quelli della nuova
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
}
else
{
dbCtx.DbSetOrder.Update(entity);
}
return await dbCtx.SaveChangesAsync() > 0;
}
public async Task<bool> UpdateCostAsync(int OrderID)
{
await using var dbCtx = await CreateContextAsync();
// recupero righe Orderta...
var offRowList = await dbCtx
.DbSetOrderRow
.Where(x => x.OrderID == OrderID)
.ToListAsync();
// If no rows found, nothing to update
if (offRowList.Count == 0) return false;
// recupero l'elenco degli itemGroup gestiti
var itemGroupList = await dbCtx
.DbSetItemGroup
.ToListAsync();
// recupero il subset item da BOM / BomAlt...
var bomGenList = await dbCtx
.DbSetItem
.Where(x => (x.ItemType == Core.Enums.ItemClassType.Bom || x.ItemType == Core.Enums.ItemClassType.BomAlt))
.ToListAsync();
// ciclo!
foreach (var currRec in offRowList)
{
// se contiene qualcosa x BOM...
if (!string.IsNullOrEmpty(currRec.ItemBOM) && currRec.ItemBOM.Length > 2)
{
// deserializzo
var bomList = JsonConvert.DeserializeObject<List<BomItemDTO>>(currRec.ItemBOM);
// se ho trovato elementi...
if (bomList != null)
{
// calcolo il NUOVO costo e lo aggiorno...
double totCost = 0;
double totPrice = 0;
int totItemQty = 0;
int numGroupOk = 0;
int numItemOk = 0;
int numElems = bomList.Count;
// validazione e completamento BOM
BomCalculator.Validate(itemGroupList, bomGenList, ref bomList, null, ref totCost, ref totPrice, ref totItemQty, ref numGroupOk, ref numItemOk);
// salvo BOM...
string itemBom = JsonConvert.SerializeObject(bomList);
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;
dbCtx.Entry(currRec).State = EntityState.Modified;
}
}
}
return await dbCtx.SaveChangesAsync() > 0;
}
#endregion Public Methods
}
}