Spostamento servizi warehouse + inserimento prime funzioni calcolo fabbisogni

This commit is contained in:
Samuele Locatelli
2026-04-17 12:07:08 +02:00
parent 863cb3d3a9
commit da7cfb9668
15 changed files with 153 additions and 54 deletions
@@ -8,6 +8,7 @@ using EgwCoreLib.Lux.Data.Services.Job;
using EgwCoreLib.Lux.Data.Services.Production;
using EgwCoreLib.Lux.Data.Services.Sales;
using EgwCoreLib.Lux.Data.Services.Utils;
using EgwCoreLib.Lux.Data.Services.Warehouse;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace EgwCoreLib.Lux.Data
@@ -39,6 +40,7 @@ namespace EgwCoreLib.Lux.Data
services.TryAddScoped<IItemRepository, ItemRepository>();
services.TryAddScoped<IJobStepRepository, JobStepRepository>();
services.TryAddScoped<IJobTaskRepository, JobTaskRepository>();
services.TryAddScoped<IMatReqRepository, MatReqRepository>();
services.TryAddScoped<IOfferRepository, OfferRepository>();
services.TryAddScoped<IOfferRowRepository, OfferRowRepository>();
services.TryAddScoped<IOrderRepository, OrderRepository>();
@@ -71,6 +73,7 @@ namespace EgwCoreLib.Lux.Data
services.TryAddScoped<IItemGroupService, ItemGroupService>();
services.TryAddScoped<IJobStepService, JobStepService>();
services.TryAddScoped<IJobTaskService, JobTaskService>();
services.TryAddScoped<IMatReqService, MatReqService>();
services.TryAddScoped<IOfferService, OfferService>();
services.TryAddScoped<IOfferRowService, OfferRowService>();
services.TryAddScoped<IOrderService, OrderService>();
@@ -22,6 +22,13 @@
/// <param name="entity">Record da eliminare</param>
Task<bool> DeleteAsync(MatReqModel entity);
/// <summary>
/// Elimina un set di record MatReq dato OrderRowId.
/// </summary>
/// <param name="orderRowId">ID dell'OrderRow relativo</param>
/// <param name="force">forza cancellazione anche per già ordinati</param>
Task<bool> DeleteByOrderRowAsync(int orderRowId, bool force = false);
/// <summary>
/// Recupera un record MatReq specifico per ID.
/// </summary>
@@ -30,6 +30,19 @@
return await dbCtx.SaveChangesAsync() > 0;
}
/// <inheritdoc />
public async Task<bool> DeleteByOrderRowAsync(int orderRowId, bool force = false)
{
await using var dbCtx = await CreateContextAsync();
// registro eliminazione diretta dei record eliminabilii...
var list2del = await dbCtx
.DbSetMaterialReq
.Where(x => x.OrderRowID == orderRowId && (!x.Processed || force))
.ExecuteDeleteAsync();
return await dbCtx.SaveChangesAsync() > 0;
}
/// <inheritdoc />
public async Task<MatReqModel?> GetByIdAsync(int recId)
{
@@ -1,4 +1,4 @@
namespace EgwCoreLib.Lux.Data.Warehouse
namespace EgwCoreLib.Lux.Data.Services.Warehouse
{
public interface IMatReqService
{
@@ -47,11 +47,14 @@
#endif
/// <summary>
/// Genera un set di MatReq da una lista di ID di RigheOrdine
/// Riconcilia i fabbisogni x un set di RigheOrdine:
/// - verifica ogni riga d'orine e le relative BOM
/// - verifica eventuali fabbisogni presenti (tiene se ordinati, elimina se solo promessi)
/// - genera un set di record fabbisogni (MatReq) per garantire evazione BOM
/// </summary>
/// <param name="ListOrderRow">Lista OrderRow da processare</param>
/// <returns></returns>
Task<bool> UpsertManyAsync(List<OrderRowModel> ListOrderRow);
Task<bool> ReconcileOrderRowsAsync(List<OrderRowModel> ListOrderRow, bool forceReset = false);
#endregion Public Methods
}
@@ -0,0 +1,93 @@
namespace EgwCoreLib.Lux.Data.Services.Warehouse
{
public class MatReqService : BaseServ, IMatReqService
{
#region Public Constructors
public MatReqService(
IConfiguration config,
IConnectionMultiplexer redis,
IMatReqRepository repo) : base(config, redis)
{
_className = "MatReq";
_repo = repo;
}
/// <inheritdoc />
public async Task<bool> ReconcileOrderRowsAsync(List<OrderRowModel> ListOrderRow, bool forceReset = false)
{
return await TraceAsync($"{_className}.ReconcileOrderRowsAsync", async (activity) =>
{
List<MatReqModel> listaSpesa = new();
// ciclo sulle righe x trasformare BOM in fabbisogni...
foreach (var currItem in ListOrderRow)
{
var newReq = await GetFabbisogniAsync(currItem, forceReset);
listaSpesa.AddRange(newReq);
}
bool success = await _repo.AddManyAsync(listaSpesa);
activity?.SetTag("db.operation", "ReconcileOrderRowsAsync");
if (success)
{
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
}
return success;
});
}
/// <summary>
/// Genera un set di record fabbisogni da un item (RigaOrdine)
/// </summary>
/// <param name="currItem">Singolo record OrderModel</param>
/// <returns></returns>
private async Task<List<MatReqModel>> GetFabbisogniAsync(OrderRowModel currItem, bool forceReset)
{
List<MatReqModel> newReqList = new();
/*--------------------------------------------------
* Calcolo fabbisogni x rigaOrine (Item)
* - elimina ogni fabbisogno precedente (DOVREBBE tenere se confermati/ordinati)
* - genera un nuovo set di fabbisogni x ogni riga della BOM dell'ITEM
*--------------------------------------------------*/
// eliminazione preliminare...
await _repo.DeleteByOrderRowAsync(currItem.OrderRowID, forceReset);
// leggo l'elenco attuale dei fabbisogni presenti
var currMatReqList = await _repo.GetFiltAsync(null, currItem.OrderRowID, null, null);
// ogni riga a 1..n BOM --> per ogni riga BOM 1 fabbisogno...
foreach (var bomItem in currItem.ListBOM)
{
// valorizzo inizialmente come record intero
MatReqModel newReq = new MatReqModel()
{
OrderRowID = currItem.OrderRowID,
Inserted = DateTime.Now,
ItemID = bomItem.ItemID,
Processed = false,
Qty = bomItem.Qty
};
// cerco nei fabbisogni...
var cMatReq = currMatReqList.FirstOrDefault(x => x.OrderRowID == currItem.OrderRowID && x.ItemID == bomItem.ItemID);
// se trovato --> genera per differenza
if (cMatReq != null)
{
newReq.Qty -= cMatReq.Qty;
}
newReqList.Add(newReq);
}
return newReqList;
}
#endregion Public Constructors
private readonly string _className;
private readonly IMatReqRepository _repo;
}
}
@@ -0,0 +1 @@
global using EgwCoreLib.Lux.Data.Repository.Warehouse;
@@ -1,46 +0,0 @@
using EgwCoreLib.Lux.Data.Services;
namespace EgwCoreLib.Lux.Data.Warehouse
{
public class MatReqService : BaseServ, IMatReqService
{
#region Public Constructors
public MatReqService(
IConfiguration config,
IConnectionMultiplexer redis,
IMatReqService repo) : base(config, redis)
{
_className = "MatReq";
_repo = repo;
}
/// <inheritdoc />
public async Task<bool> UpsertManyAsync(List<OrderRowModel> ListOrderRow)
{
return await TraceAsync($"{_className}.UpsertManyAsync", async (activity) =>
{
// per prima cosa costruisco un elenco di tutte le BOM richieste per ogn OrderRowmodel..
List<List<BomItemDTO>> listBom = ListOrderRow.Select(x => x.ListBOM).ToList();
bool success = false;
//bool success = await _repo.UpsertFromBomAsync(bomList);
activity?.SetTag("db.operation", "UpsertManyAsync");
if (success)
{
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
}
return success;
});
}
#endregion Public Constructors
private readonly string _className;
private readonly IMatReqService _repo;
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>1.1.2604.1710</Version>
<Version>1.1.2604.1712</Version>
</PropertyGroup>
<ItemGroup>
@@ -248,6 +248,9 @@ else
<span class="small">@fSize(item.Original.FileSize)</span>
</li>
}
<li class="list-group-item d-flex justify-content-between align-items-start px-2 py-1 small">
<button class="btn btn-sm btn-warning" @onclick="()=>DoGenFabbisogni(item.Original)"><i class="fa-solid fa-basket-shopping"></i></button>
</li>
</ul>
</div>
</td>
@@ -334,6 +334,9 @@ namespace Lux.UI.Components.Compo.Order
[Inject]
private IDataLayerServices DLService { get; set; } = null!;
[Inject]
private IMatReqService MRService { get; set; } = null!;
[Inject]
private IEnvirParamService EPService { get; set; } = null!;
@@ -781,6 +784,20 @@ namespace Lux.UI.Components.Compo.Order
isLoading = false;
}
private async Task DoGenFabbisogni(OrderRowModel curRec)
{
if (!await JSRuntime.InvokeAsync<bool>("confirm", $"Confermi di voler generare i fabbisogni per la riga d'ordine indicata?"))
return;
// chiamo procedura creazione fabbisogni...
List<OrderRowModel> listReq = new();
listReq.Add(curRec);
await MRService.ReconcileOrderRowsAsync(listReq);
await ReloadDataAsync();
UpdateTable();
}
/// <summary>
/// Edit del file:
/// - abilitazione fileUpload
@@ -837,6 +854,10 @@ namespace Lux.UI.Components.Compo.Order
UpdateTable();
isLoading = false;
await EC_Updated.InvokeAsync(true);
//await InvokeAsync(async () =>
//{
// await EC_Updated.InvokeAsync(true);
//});
}
/// <summary>
+1
View File
@@ -19,6 +19,7 @@ global using EgwCoreLib.Lux.Data.Services.Job;
global using EgwCoreLib.Lux.Data.Services.Production;
global using EgwCoreLib.Lux.Data.Services.Sales;
global using EgwCoreLib.Lux.Data.Services.Utils;
global using EgwCoreLib.Lux.Data.Services.Warehouse;
global using EgwCoreLib.Utils;
global using Microsoft.AspNetCore.Components;
global using Microsoft.AspNetCore.Components.Authorization;
+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.2604.1710</Version>
<Version>1.1.2604.1712</Version>
</PropertyGroup>
<ItemGroup>
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>LUX - Web Windows MES</i>
<h4>Versione: 1.1.2604.1710</h4>
<h4>Versione: 1.1.2604.1712</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
1.1.2604.1710
1.1.2604.1712
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.1.2604.1710</version>
<version>1.1.2604.1712</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>