Implementazione testata ordini

This commit is contained in:
Samuele Locatelli
2026-03-17 17:09:41 +01:00
parent f5181dd4f3
commit 0404435ec3
18 changed files with 710 additions and 535 deletions
+45 -329
View File
@@ -294,293 +294,6 @@ namespace EgwCoreLib.Lux.Data.Controllers
return dbResult;
}
#if false
/// <summary>
/// Esegue il cloning completo di un offerta e di TUTTE le relative righe di offerta...
/// </summary>
/// <param name="rec2clone"></param>
/// <returns></returns>
internal async Task<bool> OfferClone(OfferModel rec2clone)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
DateTime adesso = DateTime.Now;
// recupero offerta...
var currRec = dbCtx
.DbSetOffer
.Where(x => x.OfferID == rec2clone.OfferID)
.Include(x => x.OfferRowNav)
.FirstOrDefault();
// ultimo record OFFERTA x calcolo refNum
var lastRec = dbCtx
.DbSetOffer
.Where(x => x.RefYear == adesso.Year)
.OrderByDescending(x => x.RefNum)
.FirstOrDefault();
int newRefNum = lastRec != null ? lastRec.RefNum + 1 : 1;
// se trovo --> duplico!
if (currRec != null)
{
// recupero ultimo num offerta dell'anno corrente...
OfferModel newRec = new OfferModel()
{
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,
OffertState = OfferStates.Open,
RefNum = newRefNum,
RefRev = 1,
RefYear = adesso.Year,
ValidUntil = currRec.ValidUntil
};
// sistemo child...
newRec.OfferRowNav = currRec.OfferRowNav
.Select(c => new OfferRowModel()
{
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 = c.Modified,
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,
//OrderID = dbRec.OrderID,
OfferRowUID = c.OfferRowDtx
})
.ToList();
// infine aggiungo riga ordine e relativi child
dbCtx.DbSetOffer.Add(newRec);
}
// salvo TUTTI i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OfferClone{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Elenco completo offerte da DB
/// </summary>
/// <returns></returns>
internal async Task<List<OfferModel>> OfferGetAll()
{
List<OfferModel> dbResult = new List<OfferModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = await dbCtx
.DbSetOffer
.Include(c => c.CustomerNav)
.Include(d => d.DealerNav)
.Include(o => o.OfferRowNav)
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OfferGetAll{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Elenco offerte da DB filtrate x periodo e stato
/// </summary>
/// <param name="inizio"></param>
/// <param name="fine"></param>
/// <returns></returns>
internal async Task<List<OfferModel>> OfferGetFilt(DateTime inizio, DateTime fine)
{
List<OfferModel> dbResult = new List<OfferModel>();
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
dbResult = await dbCtx
.DbSetOffer
.Where(x => x.Inserted >= inizio && x.Inserted <= fine)
.Include(c => c.CustomerNav)
.Include(d => d.DealerNav)
.Include(o => o.OfferRowNav)
.ToListAsync();
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OfferGetFilt{Environment.NewLine}{exc}");
}
}
return dbResult;
}
/// <summary>
/// Effettua update dei costi di tutte le righe dell'offerta indicata
/// </summary>
/// <param name="OfferID"></param>
/// <returns></returns>
internal async Task<bool> OffertUpdateCost(int OfferID)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero righe offerta...
var offRowList = dbCtx
.DbSetOfferRow
.Where(x => x.OfferID == OfferID)
.ToList();
// recupero l'elenco degli itemGroup gestiti
var itemGroupList = dbCtx
.DbSetItemGroup
.ToList();
// recupero il subset item da BOM / BomAlt...
var bomGenList = dbCtx
.DbSetItem
.Where(x => (x.ItemType == Core.Enums.ItemClassType.Bom || x.ItemType == Core.Enums.ItemClassType.BomAlt))
.ToList();
// 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;
}
}
}
// salvo TUTTI i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OffertUpdateCost{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Add record offerta
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
internal async Task<bool> OffertUpsert(OfferModel updRec)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero offerta...
var currRec = dbCtx
.DbSetOffer
.Where(x => x.OfferID == updRec.OfferID)
.FirstOrDefault();
// se non trovo aggiungo
if (currRec == null)
{
dbCtx.DbSetOffer.Add(updRec);
}
// altrimenti aggiorno
else
{
// verifico eventuale riapertura SE fosse expired ma la data è valida...
if (currRec.OffertState == OfferStates.Expired && updRec.ValidUntil > DateTime.Today)
{
updRec.OffertState = OfferStates.Open;
}
dbCtx.Entry(currRec).CurrentValues.SetValues(updRec);
}
// salvo TUTTI i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OffertUpsert{Environment.NewLine}{exc}");
}
}
return answ;
}
#endif
/// <summary>
/// Recupera da DB riga offerta dato Primary ID
/// </summary>
@@ -1126,6 +839,7 @@ namespace EgwCoreLib.Lux.Data.Controllers
return answ;
}
#if false
/// <summary>
/// Restituisce record ordine + righe Ordine dato ID
/// </summary>
@@ -1303,7 +1017,7 @@ namespace EgwCoreLib.Lux.Data.Controllers
catch (Exception exc)
{
await transaction.RollbackAsync();
Log.Error($"Eccezione durante OrderFromOffer{Environment.NewLine}{exc}");
Log.Error($"Eccezione durante CloneOfferAsync{Environment.NewLine}{exc}");
}
}
return newRec;
@@ -1339,6 +1053,49 @@ namespace EgwCoreLib.Lux.Data.Controllers
return dbResult;
}
/// <summary>
/// Add record
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
internal async Task<bool> OrderUpsert(OrderModel updRec)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero offerta...
var currRec = dbCtx
.DbSetOrder
.Where(x => x.OrderID == updRec.OrderID)
.FirstOrDefault();
// se non trovo aggiungo
if (currRec == null)
{
dbCtx.DbSetOrder.Add(updRec);
}
// altrimenti aggiorno
else
{
dbCtx.Entry(currRec).CurrentValues.SetValues(updRec);
}
// salvo TUTTI i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderUpsert{Environment.NewLine}{exc}");
}
}
return answ;
}
#endif
/// <summary>
/// Elimina riga e sposta eventuali righe successive...
/// </summary>
@@ -1957,47 +1714,6 @@ namespace EgwCoreLib.Lux.Data.Controllers
return answ;
}
/// <summary>
/// Add record
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
internal async Task<bool> OrderUpsert(OrderModel updRec)
{
bool answ = false;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
try
{
// recupero offerta...
var currRec = dbCtx
.DbSetOrder
.Where(x => x.OrderID == updRec.OrderID)
.FirstOrDefault();
// se non trovo aggiungo
if (currRec == null)
{
dbCtx.DbSetOrder.Add(updRec);
}
// altrimenti aggiorno
else
{
dbCtx.Entry(currRec).CurrentValues.SetValues(updRec);
}
// salvo TUTTI i cambiamenti...
var result = await dbCtx.SaveChangesAsync();
answ = result > 0;
}
catch (Exception exc)
{
Log.Error($"Eccezione durante OrderUpsert{Environment.NewLine}{exc}");
}
}
return answ;
}
/// <summary>
/// Elenco record Fasi da DB
@@ -1,4 +1,5 @@
using EgwCoreLib.Lux.Data.DbModel.Sales;
using EgwCoreLib.Lux.Data.DbModel.Items;
using EgwCoreLib.Lux.Data.DbModel.Sales;
namespace EgwCoreLib.Lux.Data.Repository.Sales
{
@@ -8,14 +9,28 @@ namespace EgwCoreLib.Lux.Data.Repository.Sales
Task<bool> AddAsync(OrderModel entity);
Task<OrderModel?> CloneOfferAsync(OfferModel rec2clone);
Task<bool> DeleteAsync(OrderModel entity);
Task<List<OrderModel>> GetAllAsync();
Task<List<ItemModel>> GetBomItemsAsync();
Task<OrderModel?> GetByIdAsync(int recId);
Task<List<OrderModel>> GetFiltAsync(DateTime inizio, DateTime fine);
Task<List<ItemGroupModel>> GetItemGroupsAsync();
Task<List<OrderRowModel>> GetRowsAsync(int recId);
Task<bool> SaveRowsAsync(List<OrderRowModel> rows);
Task<bool> UpdateAsync(OrderModel entity);
Task<bool> UpdateCostAsync(int OrderID);
#endregion Public Methods
}
}
@@ -0,0 +1,328 @@
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
using var transaction = 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 transaction.CommitAsync();
}
}
catch
{
await transaction.RollbackAsync();
// sollevo exception
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)
{
await using var dbCtx = await CreateContextAsync();
foreach (var row in rows)
dbCtx.Entry(row).State = EntityState.Modified;
return await dbCtx.SaveChangesAsync() > 0;
}
public async Task<bool> UpdateAsync(OrderModel entity)
{
await using var dbCtx = await CreateContextAsync();
// Recuperiamo l'entità tracciata dal context
var trackedEntity = dbCtx.DbSetOrder.Local.FirstOrDefault(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();
// 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
}
}
+58 -183
View File
@@ -316,154 +316,6 @@ namespace EgwCoreLib.Lux.Data.Services
return result;
}
#if false
/// <summary>
/// Esegue clone completo dell'offerta indicata e svuota la cache
/// </summary>
/// <param name="rec2clone"></param>
/// <returns></returns>
public async Task<bool> OfferClone(OfferModel rec2clone)
{
using var activity = StartActivity();
string source = "DB+REDIS";
// calcolo
bool fatto = await dbController.OfferClone(rec2clone);
// svuoto cache...
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:Offers:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OfferRows:*");
activity?.SetTag("data.source", source);
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms");
return fatto;
}
/// <summary>
/// Elenco completo offerte da DB
/// </summary>
/// <returns></returns>
public async Task<List<OfferModel>> OfferGetAll()
{
using var activity = StartActivity();
string source = "DB";
List<OfferModel>? result = new List<OfferModel>();
// cerco in redis...
string currKey = $"{redisBaseKey}:Offers:ALL";
RedisValue rawData = await _redisDb.StringGetAsync(currKey);
//if (!string.IsNullOrEmpty($"{rawData}"))
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<OfferModel>>($"{rawData}");
source = "REDIS";
}
else
{
result = await dbController.OfferGetAll();
// serializzo e salvo con config x evitare loop...
rawData = JsonConvert.SerializeObject(result, JSSettings);
await _redisDb.StringSetAsync(currKey, rawData, LongCache);
}
if (result == null)
{
result = new List<OfferModel>();
}
activity?.SetTag("data.source", source);
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Elenco offerte da DB filtrate x periodo e stato
/// </summary>
/// <param name="inizio"></param>
/// <param name="fine"></param>
/// <returns></returns>
public async Task<List<OfferModel>> OfferGetFilt(DateTime inizio, DateTime fine)
{
using var activity = StartActivity();
string source = "DB";
List<OfferModel>? result = new List<OfferModel>();
// cerco in redis...
string currKey = $"{redisBaseKey}:Offers:Filt:{inizio:yyMMdd-HHmm}:{fine:yyMMdd-HHmm}";
RedisValue rawData = await _redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<OfferModel>>($"{rawData}");
source = "REDIS";
}
else
{
result = await dbController.OfferGetFilt(inizio, fine);
// serializzo e salvo con config x evitare loop...
rawData = JsonConvert.SerializeObject(result, JSSettings);
await _redisDb.StringSetAsync(currKey, rawData, LongCache);
}
if (result == null)
{
result = new List<OfferModel>();
}
activity?.SetTag("data.source", source);
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Effettua update dei costi di tutte le righe dell'offerta indicata
/// </summary>
/// <param name="OfferID">Key</param>
/// <returns></returns>
public async Task<bool> OffertUpdateCost(int OfferID)
{
using var activity = StartActivity();
string source = "DB+REDIS";
// calcolo
bool fatto = await dbController.OffertUpdateCost(OfferID);
// svuoto cache...
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:Offers:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OfferRows:*");
activity?.SetTag("data.source", source);
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms");
return fatto;
}
/// <summary>
/// Effettua Add complessivo record offerta
/// </summary>
/// <param name="updRec">Key</param>
/// <returns></returns>
public async Task<bool> OffertUpsert(OfferModel updRec)
{
using var activity = StartActivity();
string source = "DB+REDIS";
// calcolo
bool fatto = await dbController.OffertUpsert(updRec);
// svuoto cache...
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:Offers:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OfferRows:*");
activity?.SetTag("data.source", source);
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms");
return fatto;
}
#endif
/// <summary>
/// Effettua update dei costi di tutte le righe dell'ordine indicata
/// </summary>
/// <param name="OfferID">Key</param>
/// <returns></returns>
public async Task<bool> OrderUpdateCost(int OrderID)
{
using var activity = StartActivity();
bool fatto = false;
string source = "DB+REDIS";
// calcolo
#if false
fatto = await dbController.OrderUpdateCost(OrderID);
#endif
// svuoto cache...
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:Offers:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OfferRows:*");
activity?.SetTag("data.source", source);
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms");
return fatto;
}
/// <summary>
/// Elenco righe offerta specificata
/// </summary>
@@ -799,6 +651,26 @@ namespace EgwCoreLib.Lux.Data.Services
}
#if false
/// <summary>
/// Effettua update dei costi di tutte le righe dell'ordine indicata
/// </summary>
/// <param name="OfferID">Key</param>
/// <returns></returns>
public async Task<bool> OrderUpdateCost(int OrderID)
{
using var activity = StartActivity();
bool fatto = false;
string source = "DB+REDIS";
// calcolo
//fatto = await dbController.OrderUpdateCost(OrderID);
// svuoto cache...
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:Offers:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OfferRows:*");
activity?.SetTag("data.source", source);
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms");
return fatto;
}
/// <summary>
/// Restituisce record ordine + righe Ordine dato ID
/// </summary>
@@ -859,22 +731,6 @@ namespace EgwCoreLib.Lux.Data.Services
return newOrd;
}
/// <summary>
/// Converte il campo raw della BOM in lista oggetti da gestire
/// </summary>
/// <param name="currRec"></param>
/// <returns></returns>
public List<BomItemDTO> OrderGetBomList(OrderRowModel currRec)
{
List<BomItemDTO> answ = new List<BomItemDTO>();
var bomList = JsonConvert.DeserializeObject<List<BomItemDTO>>(currRec.ItemBOM);
if (bomList != null)
{
answ = bomList;
}
return answ;
}
/// <summary>
/// Elenco ordini da DB filtrate x periodo e stato
/// </summary>
@@ -910,6 +766,44 @@ namespace EgwCoreLib.Lux.Data.Services
return result;
}
/// <summary>
/// Effettua upsert complessivo Ordine
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
public async Task<bool> OrderUpsert(OrderModel updRec)
{
using var activity = StartActivity();
string source = "DB+REDIS";
// calcolo
bool fatto = await dbController.OrderUpsert(updRec);
// svuoto cache...
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:Orders:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OrderRows:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OrderRowsByState:*");
activity?.SetTag("data.source", source);
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms");
return fatto;
}
#endif
/// <summary>
/// Converte il campo raw della BOM in lista oggetti da gestire
/// </summary>
/// <param name="currRec"></param>
/// <returns></returns>
public List<BomItemDTO> OrderGetBomList(OrderRowModel currRec)
{
List<BomItemDTO> answ = new List<BomItemDTO>();
var bomList = JsonConvert.DeserializeObject<List<BomItemDTO>>(currRec.ItemBOM);
if (bomList != null)
{
answ = bomList;
}
return answ;
}
/// <summary>
/// Effettua eliminazione della riga Ordine
/// </summary>
@@ -1214,25 +1108,6 @@ namespace EgwCoreLib.Lux.Data.Services
return fatto;
}
/// <summary>
/// Effettua upsert complessivo Ordine
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
public async Task<bool> OrderUpsert(OrderModel updRec)
{
using var activity = StartActivity();
string source = "DB+REDIS";
// calcolo
bool fatto = await dbController.OrderUpsert(updRec);
// svuoto cache...
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:Orders:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OrderRows:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OrderRowsByState:*");
activity?.SetTag("data.source", source);
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms");
return fatto;
}
/// <summary>
/// Elenco completo Fasi
@@ -0,0 +1,21 @@
using EgwCoreLib.Lux.Data.DbModel.Sales;
namespace EgwCoreLib.Lux.Data.Services.Sales
{
public interface IOrderService
{
#region Public Methods
Task<OrderModel?> CloneOfferAsync(OfferModel rec2clone);
Task<List<OrderModel>> GetFiltAsync(DateTime inizio, DateTime fine);
Task<OrderModel?> GetByIdAsync(int recId, bool doForce);
Task<bool> UpsertAsync(OrderModel upsRec);
Task<bool> UpdateCostAsync(int OrderId);
#endregion Public Methods
}
}
@@ -89,7 +89,7 @@ namespace EgwCoreLib.Lux.Data.Services.Sales
/// <returns></returns>
public async Task<bool> UpdateCostAsync(int OfferId)
{
return await TraceAsync($"{_className}.Upsert", async (activity) =>
return await TraceAsync($"{_className}.UpdateCost", async (activity) =>
{
// 1. Recupero dati
var rows = await _repo.GetRowsAsync(OfferId);
@@ -0,0 +1,201 @@
using EgwCoreLib.Lux.Core.RestPayload;
using EgwCoreLib.Lux.Data.DbModel.Sales;
using EgwCoreLib.Lux.Data.Domains;
using EgwCoreLib.Lux.Data.Repository.Sales;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using StackExchange.Redis;
namespace EgwCoreLib.Lux.Data.Services.Sales
{
public class OrderService : BaseServ, IOrderService
{
#region Public Constructors
public OrderService(
IConfiguration config,
IConnectionMultiplexer redis,
IOrderRepository repo) : base(config, redis)
{
_className = "Order";
_repo = repo;
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Genera un nuovo record ordine:
/// - cloning completo di un offerta + TUTTE le relative righe di offerta + rif offerta
/// - generazione prodItems x etichette
/// </summary>
/// <param name="rec2clone"></param>
/// <returns></returns>
public async Task<OrderModel?> CloneOfferAsync(OfferModel rec2clone)
{
return await TraceAsync($"{_className}.CloneOffer", async (activity) =>
{
// eseguo clone
var result = await _repo.CloneOfferAsync(rec2clone);
// se eseguito, pulisco la cache correlata
if (result != null)
{
// Invalido sia la lista classi che eventuali dettagli correlati
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
await ClearCacheAsync($"{_redisBaseKey}:OrderRows:*");
await ClearCacheAsync($"{_redisBaseKey}:OrderRowsByState:*");
}
return result;
});
}
public async Task<OrderModel?> GetByIdAsync(int recId, bool doForce)
{
// Uso helper TraceAsync che gestisce automaticamente StartActivity, Log e Exception tracking
return await TraceAsync($"{_className}.GetFilt", async (activity) =>
{
if (doForce)
{
return await _repo.GetByIdAsync(recId) ?? new OrderModel();
}
else
{
return await GetOrSetCacheAsync(
$"{_redisBaseKey}:{_className}:ById:{recId}",
async () => await _repo.GetByIdAsync(recId),
LongCache
);
}
});
}
/// <summary>
/// Elenco completo Order da DB
/// </summary>
/// <returns></returns>
public async Task<List<OrderModel>> 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 Order indicato
/// </summary>
/// <param name="OrderId"></param>
/// <returns></returns>
public async Task<bool> UpdateCostAsync(int OrderId)
{
return await TraceAsync($"{_className}.UpdateCost", async (activity) =>
{
// 1. Recupero dati
var rows = await _repo.GetRowsAsync(OrderId);
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 ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
await ClearCacheAsync($"{_redisBaseKey}:OrderRows:*");
await ClearCacheAsync($"{_redisBaseKey}:OrderRowsByState:*");
}
return result;
});
}
/// <summary>
/// Upsert record Order
/// </summary>
/// <param name="updRec"></param>
/// <returns></returns>
public async Task<bool> UpsertAsync(OrderModel upsRec)
{
return await TraceAsync($"{_className}.Upsert", async (activity) =>
{
var currRec = await _repo.GetByIdAsync(upsRec.OrderID);
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 ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
await ClearCacheAsync($"{_redisBaseKey}:OrderRows:*");
await ClearCacheAsync($"{_redisBaseKey}:OrderRowsByState:*");
}
return success;
});
}
#endregion Public Methods
#region Private Fields
private readonly string _className;
private readonly IOrderRepository _repo;
#endregion Private Fields
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>1.1.2603.1716</Version>
<Version>1.1.2603.1717</Version>
</PropertyGroup>
<ItemGroup>
+2
View File
@@ -183,6 +183,7 @@ builder.Services.AddScoped<IItemRepository, ItemRepository>();
builder.Services.AddScoped<IJobStepRepository, JobStepRepository>();
builder.Services.AddScoped<IJobTaskRepository, JobTaskRepository>();
builder.Services.AddScoped<IOfferRepository, OfferRepository>();
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddScoped<IResourceRepository, ResourceRepository>();
builder.Services.AddScoped<ISellingItemRepository, SellingItemRepository>();
builder.Services.AddScoped<ITemplateRepository, TemplateRepository>();
@@ -199,6 +200,7 @@ builder.Services.AddScoped<IItemService, ItemService>();
builder.Services.AddScoped<IJobStepService, JobStepService>();
builder.Services.AddScoped<IJobTaskService, JobTaskService>();
builder.Services.AddScoped<IOfferService, OfferService>();
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddScoped<IResourceService, ResourceService>();
builder.Services.AddScoped<ISellingItemService, SellingItemService>();
builder.Services.AddScoped<ITemplateService, TemplateService>();
+6 -2
View File
@@ -8,6 +8,7 @@ using EgwCoreLib.Lux.Data.DbModel.Sales;
using EgwCoreLib.Lux.Data.DbModel.Utils;
using EgwCoreLib.Lux.Data.Services;
using EgwCoreLib.Lux.Data.Services.Config;
using EgwCoreLib.Lux.Data.Services.Sales;
using EgwCoreLib.Lux.Data.Services.Utils;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
@@ -362,6 +363,9 @@ namespace Lux.UI.Components.Compo
[Inject]
private DataLayerServices DLService { get; set; } = null!;
[Inject]
private IOrderService OrdService { get; set; } = null!;
[Inject]
private IEnvirParamService EPService { get; set; } = null!;
@@ -820,7 +824,7 @@ namespace Lux.UI.Components.Compo
await InvokeAsync(StateHasChanged);
await Task.Delay(300);
}
await DLService.OrderUpdateCost(OrderID);
await OrdService.UpdateCostAsync(OrderID);
if (forceResetCalc)
{
await Task.Delay(300);
@@ -1528,7 +1532,7 @@ namespace Lux.UI.Components.Compo
IconCss = "fa-solid fa-hourglass-start"
});
CurrRecord.LogHistory = currHist;
await DLService.OrderUpsert(CurrRecord);
await OrdService.UpsertAsync(CurrRecord);
}
}
+11 -8
View File
@@ -71,7 +71,10 @@ namespace Lux.UI.Components.Pages
protected IJSRuntime JSRuntime { get; set; } = null!;
[Inject]
private IOfferService OService { get; set; } = default!;
private IOfferService OffService { get; set; } = default!;
[Inject]
private IOrderService OrdService { get; set; } = default!;
[Inject]
@@ -111,7 +114,7 @@ namespace Lux.UI.Components.Pages
if (!await JSRuntime.InvokeAsync<bool>("confirm", $"Confermi di voler duplicare interamente l'offerta selezionata?{Environment.NewLine}---------------------------{Environment.NewLine}Env: {rec2clone.Envir} | {rec2clone.OfferCode}{Environment.NewLine}{rec2clone.Description}{Environment.NewLine}Articoli: {rec2clone.NumItems}{Environment.NewLine}---------------------------{Environment.NewLine}Importo: {rec2clone.TotalPrice:C2}"))
return;
// clona intera offerta + tutte le righe...
await OService.CloneAsync(rec2clone);
await OffService.CloneAsync(rec2clone);
await ReloadData();
UpdateTable();
}
@@ -129,7 +132,7 @@ namespace Lux.UI.Components.Pages
if (!await JSRuntime.InvokeAsync<bool>("confirm", $"Vuoi uscire salvando?"))
return;
// salvo record
await OService.UpsertAsync(updRec);
await OffService.UpsertAsync(updRec);
}
protected void DoSelect(OfferModel curRec)
@@ -192,7 +195,7 @@ namespace Lux.UI.Components.Pages
return;
// creazione nuovo ordine da offerta
var newOrd = await DLService.OrderFromOffer(currRec);
var newOrd = await OrdService.CloneOfferAsync(currRec);
if (newOrd != null)
{
@@ -274,7 +277,7 @@ namespace Lux.UI.Components.Pages
});
newOrd.LogHistory = currHist;
//OrderHist = listOrdRow.LogHistory;
await DLService.OrderUpsert(newOrd);
await OrdService.UpsertAsync(newOrd);
}
}
}
@@ -282,7 +285,7 @@ namespace Lux.UI.Components.Pages
}
currRec.OffertState = newStatus;
await OService.UpsertAsync(currRec);
await OffService.UpsertAsync(currRec);
await ReloadData();
UpdateTable();
}
@@ -397,7 +400,7 @@ namespace Lux.UI.Components.Pages
private async Task DoSave(OfferModel updRec)
{
// salvo record
await OService.UpsertAsync(updRec);
await OffService.UpsertAsync(updRec);
// cambio step
CompileStep nextStep = currStep < CompileStep.FinalCheck ? currStep + 1 : currStep;
AdvStep(nextStep);
@@ -448,7 +451,7 @@ namespace Lux.UI.Components.Pages
private async Task ReloadData()
{
await DLService.OffersCheckExpired();
AllRecords = await OService.GetFiltAsync(PeriodoSel.Inizio, PeriodoSel.Fine);
AllRecords = await OffService.GetFiltAsync(PeriodoSel.Inizio, PeriodoSel.Fine);
DoFilter();
}
+8 -4
View File
@@ -5,6 +5,7 @@ using EgwCoreLib.Lux.Data.DbModel.Config;
using EgwCoreLib.Lux.Data.DbModel.Sales;
using EgwCoreLib.Lux.Data.Services;
using EgwCoreLib.Lux.Data.Services.Config;
using EgwCoreLib.Lux.Data.Services.Sales;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using NLog;
@@ -46,6 +47,9 @@ namespace Lux.UI.Components.Pages
[Inject]
protected DataLayerServices DLService { get; set; } = null!;
[Inject]
private IOrderService OrdService { get; set; } = null!;
[Inject]
private IEnvirParamService EPService { get; set; } = null!;
@@ -156,7 +160,7 @@ namespace Lux.UI.Components.Pages
currRec.LogHistory = new List<TaskHistDTO>();
OrderHist = currRec.LogHistory;
await DLService.OrderUpsert(currRec);
await OrdService.UpsertAsync(currRec);
}
/// <summary>
@@ -306,7 +310,7 @@ namespace Lux.UI.Components.Pages
});
currRec.LogHistory = currHist;
OrderHist = currRec.LogHistory;
await DLService.OrderUpsert(currRec);
await OrdService.UpsertAsync(currRec);
}
}
}
@@ -435,7 +439,7 @@ namespace Lux.UI.Components.Pages
private async Task DoSave(OrderModel updRec)
{
// salvo record
await DLService.OrderUpsert(updRec);
await OrdService.UpsertAsync(updRec);
// cambio step
CompileStep nextStep = currStep < CompileStep.FinalCheck ? currStep + 1 : currStep;
AdvStep(nextStep);
@@ -525,7 +529,7 @@ namespace Lux.UI.Components.Pages
private async Task ReloadData()
{
await DLService.OffersCheckExpired();
AllRecords = await DLService.OrderGetFilt(PeriodoSel.Inizio, PeriodoSel.Fine);
AllRecords = await OrdService.GetFiltAsync(PeriodoSel.Inizio, PeriodoSel.Fine);
DoFilter();
}
@@ -4,6 +4,7 @@ using EgwCoreLib.Lux.Data.DbModel.Production;
using EgwCoreLib.Lux.Data.DbModel.Sales;
using EgwCoreLib.Lux.Data.DbModel.Utils;
using EgwCoreLib.Lux.Data.Services;
using EgwCoreLib.Lux.Data.Services.Sales;
using EgwCoreLib.Lux.Data.Services.Utils;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
@@ -83,6 +84,9 @@ namespace Lux.UI.Components.Pages
[Inject]
private IJSRuntime JSRuntime { get; set; } = null!;
[Inject]
private IOrderService OrdService { get; set; } = null!;
[Inject]
private ProdService PService { get; set; } = null!;
@@ -429,7 +433,7 @@ namespace Lux.UI.Components.Pages
var currPOR = ListEstimRecords?.FirstOrDefault(x => x.OrderRowID == prodGroupItem.OrderRowID) ?? new OrderRowModel();
var currRec = await DLService.OrderById(currPOR.OrderID, true);
var currRec = await OrdService.GetByIdAsync(currPOR.OrderID, true);
var dictReq = new Dictionary<string, double>();
// verifico se ho 1 sola macchina o molte...
@@ -502,7 +506,7 @@ namespace Lux.UI.Components.Pages
IconCss = "fa-solid fa-hourglass-start"
});
currRec.LogHistory = currHist;
await DLService.OrderUpsert(currRec);
await OrdService.UpsertAsync(currRec);
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspnet-Lux.UI-a758c101-a2f4-4e38-977d-1c4887dbbd50</UserSecretsId>
<Version>1.1.2603.1716</Version>
<Version>1.1.2603.1717</Version>
</PropertyGroup>
<ItemGroup>
+2
View File
@@ -221,6 +221,7 @@ builder.Services.AddScoped<IItemRepository, ItemRepository>();
builder.Services.AddScoped<IJobStepRepository, JobStepRepository>();
builder.Services.AddScoped<IJobTaskRepository, JobTaskRepository>();
builder.Services.AddScoped<IOfferRepository, OfferRepository>();
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddScoped<IResourceRepository, ResourceRepository>();
builder.Services.AddScoped<ISellingItemRepository, SellingItemRepository>();
builder.Services.AddScoped<ITemplateRepository, TemplateRepository>();
@@ -237,6 +238,7 @@ builder.Services.AddScoped<IItemService, ItemService>();
builder.Services.AddScoped<IJobStepService, JobStepService>();
builder.Services.AddScoped<IJobTaskService, JobTaskService>();
builder.Services.AddScoped<IOfferService, OfferService>();
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddScoped<IResourceService, ResourceService>();
builder.Services.AddScoped<ISellingItemService, SellingItemService>();
builder.Services.AddScoped<ITemplateService, TemplateService>();
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>LUX - Web Windows MES</i>
<h4>Versione: 1.1.2603.1716</h4>
<h4>Versione: 1.1.2603.1717</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
1.1.2603.1716
1.1.2603.1717
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.1.2603.1716</version>
<version>1.1.2603.1717</version>
<url>http://nexus.steamware.net/repository/SWS/GPW/stable/GPW.UI.zip</url>
<changelog>http://nexus.steamware.net/repository/SWS/GPW/stable/ChangeLog.html</changelog>
<mandatory>false</mandatory>