350 lines
14 KiB
C#
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
|
|
}
|
|
}
|