Aggiunta metodi x creazione ODL e item2odl (DA PROVARE!!!)

This commit is contained in:
Samuele Locatelli
2026-01-21 12:36:10 +01:00
parent ceb35ebe9e
commit 95ea5c504f
13 changed files with 667 additions and 158 deletions
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EgwCoreLib.Lux.Core.Generic
{
public class GroupDetailDTO
{
#region Public Properties
public string MachineName { get; set; } = "";
public List<string> TagList { get; set; } = new List<string>();
public int TotalBarQty { get; set; } = 0;
public int TotalNumPart { get; set; } = 0;
public decimal TotalTime { get; set; } = 0;
#endregion Public Properties
}
}
@@ -16,6 +16,7 @@ using NLog;
using StackExchange.Redis;
using System.Data;
using System.Globalization;
using ZXing;
using static EgwCoreLib.Lux.Core.Enums;
namespace EgwCoreLib.Lux.Data.Controllers
@@ -3516,6 +3517,137 @@ namespace EgwCoreLib.Lux.Data.Controllers
return dbResult;
}
/// <summary>
/// Creazione di un Batch con relativo Tag e info x creazione ODL correlati
/// </summary>
/// <param name="newRec"></param>
/// <returns></returns>
internal async Task<ProductionBatchModel?> ProductionBatchCreateAsync(ProductionBatchModel newRec)
{
ProductionBatchModel dbResult = null;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// avvio transazione
using var transaction = await dbCtx.Database.BeginTransactionAsync();
try
{
int currentYear = DateTime.Today.Year;
string prefix = "BC.";
// 1. Chiamata alla Stored Procedure per ottenere il nuovo ID
// Definiamo il parametro di output
var outputParam = new MySqlParameter
{
ParameterName = "pValue",
DbType = DbType.Int32,
Direction = ParameterDirection.Output
};
await dbCtx.Database.ExecuteSqlRawAsync(
"CALL GetNextCounter(@pYear, @pName, @pValue)",
new MySqlParameter("@pYear", currentYear),
new MySqlParameter("@pName", prefix),
outputParam
);
int idx = (int)outputParam.Value;
// 2. Formattazione del BatchTag secondo le tue specifiche
// :x8 formatta in esadecimale (lowercase) con padding di 8 zeri
string formattedTag = $"{prefix}{currentYear}{idx:x8}";
// 3. Creazione del nuovo record
dbResult = new ProductionBatchModel
{
Description = newRec.Description,
DueDate = newRec.DueDate,
BatchTag = formattedTag.ToUpper()
};
dbCtx.DbSetProdBatch.Add(dbResult);
// salvo!
await dbCtx.SaveChangesAsync();
// 4. Commit della transazione
await transaction.CommitAsync();
return dbResult;
}
catch (Exception)
{
await transaction.RollbackAsync();
throw;
}
}
}
/// <summary>
/// Insert sul DB di un elenco ODL con calcolo della relativa KEY a cui poter, successivamente, collegare i record child (items)
/// </summary>
/// <param name="listOdl2ins"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
internal async Task<List<ProductionODLModel>> ProductionOdlCreateAsync(List<ProductionODLModel> listOdl2ins)
{
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
// avvio transazione
using var transaction = await dbCtx.Database.BeginTransactionAsync();
try
{
int currentYear = DateTime.Today.Year;
string prefix = "ODL.";
foreach (var odl in listOdl2ins)
{
// 1. Chiamata alla Stored Procedure per ogni riga
var outputParam = new MySqlParameter
{
ParameterName = "pValue",
DbType = DbType.Int32,
Direction = ParameterDirection.Output
};
await dbCtx.Database.ExecuteSqlRawAsync(
"CALL GetNextCounter(@pYear, @pName, @pValue)",
new MySqlParameter("@pYear", currentYear),
new MySqlParameter("@pName", prefix),
outputParam
);
int idx = (int)outputParam.Value;
// 2. Assegnazione dati calcolati
odl.OdlTag = $"{prefix}{currentYear}{idx:X8}";
// Assicuriamoci che l'ID sia 0 per l'insert
odl.ProdODLID = 0;
dbCtx.DbSetProdODL.Add(odl);
}
// 3. Salvataggio massivo
// EF Core 8 ottimizzerà gli insert in batch dove possibile
await dbCtx.SaveChangesAsync();
// 4. Conferma transazione
await transaction.CommitAsync();
// A questo punto, ogni oggetto in 'listOdl2ins' ha il ProdODLID aggiornato dal DB
return listOdl2ins;
}
catch (Exception ex)
{
await transaction.RollbackAsync();
// Logga l'errore secondo le tue necessità
throw new Exception("Errore durante la creazione massiva degli ODL", ex);
}
}
}
/// <summary>
/// Elenco record ProductionGroup dato OrderRow
/// </summary>
@@ -3684,6 +3816,114 @@ namespace EgwCoreLib.Lux.Data.Controllers
return totalUpdated;
}
/// <summary>
/// Assegnazione in blocco degli item agli ODL corrispondenti
/// </summary>
/// <param name="dbList"></param>
/// <param name="dictParts"></param>
/// <returns></returns>
internal async Task<int> ProdItem2ODL_AssignAsync(List<ProductionODLModel> dbList, Dictionary<(int phaseId, int resId, string machine, int index), List<string>> dictParts)
{
int totalCreated = 0;
using (DataLayerContext dbCtx = new DataLayerContext())
{
// 1. Recuperiamo tutti i ProdBatchID coinvolti per fare una sola query
var batchIds = dbList.Select(o => o.ProdBatchID).Distinct().ToList();
if (batchIds != null && batchIds.Count > 0)
{
// 2. Carichiamo in memoria i ProdItem necessari (solo ID e Tag per risparmiare RAM)
// Creiamo un dizionario dove la chiave è il Tag e il valore è l'ID
var itemLookup = await dbCtx.DbSetProdItem
.Where(x => batchIds.Contains(x.ProdBatchID))
.Select(x => new { x.ProdItemID, x.ProdItemTag })
.ToDictionaryAsync(x => x.ProdItemTag, x => x.ProdItemID);
using var transaction = await dbCtx.Database.BeginTransactionAsync();
try
{
var relationsToInsert = new List<ProductionItem2ODLModel>();
foreach (var odl in dbList)
{
var key = (odl.PhaseID ?? 0, odl.ResourceID ?? 0, odl.ProdPlantCod, odl.Index);
if (dictParts.TryGetValue(key, out List<string> tagList))
{
foreach (var tag in tagList)
{
// 3. Cerchiamo l'ID corrispondente al tag nel nostro lookup locale
if (itemLookup.TryGetValue(tag, out int realItemId))
{
relationsToInsert.Add(new ProductionItem2ODLModel
{
ProdODLID = odl.ProdODLID,
ProdItemID = realItemId,
DtAssign = DateTime.Now
});
}
else
{
//Log.Warning($"Tag {tag} non trovato nel database per i batch selezionati.");
}
}
}
}
if (relationsToInsert.Any())
{
await dbCtx.DbSetProdItem2ODL.AddRangeAsync(relationsToInsert);
totalCreated = relationsToInsert.Count;
await dbCtx.SaveChangesAsync();
}
await transaction.CommitAsync();
}
catch (Exception exc)
{
await transaction.RollbackAsync();
Log.Error($"Errore nel salvataggio relazioni ODL-Parts: {exc.Message}");
throw;
}
}
}
return totalCreated;
}
/// <summary>
/// Esegue assegnazione bulk dei ProdItem ad un unico ProdBatch parent (per ora totale x RigaOrd)
/// </summary>
/// <param name="OrderRowId"></param>
/// <param name="ProdBatchId"></param>
/// <returns></returns>
internal async Task<int> ProdItemBulkAssignProdBatch(int OrderRowId, int ProdBatchId)
{
int totalUpdated = 0;
//using (DataLayerContext dbCtx = new DataLayerContext(_config))
using (DataLayerContext dbCtx = new DataLayerContext())
{
using var transaction = await dbCtx.Database.BeginTransactionAsync();
try
{
int rowsAffected = await dbCtx.DbSetProdItem
.Where(p => p.OrderRowID == OrderRowId)
.ExecuteUpdateAsync(setters => setters
.SetProperty(p => p.ProdBatchID, ProdBatchId)
);
totalUpdated += rowsAffected;
await transaction.CommitAsync();
}
catch (Exception exc)
{
await transaction.RollbackAsync();
Log.Error($"Eccezione durante ProdItemBulkAssignProdBatch{Environment.NewLine}{exc}");
//throw;
}
}
return totalUpdated;
}
/// <summary>
/// Elenco ProdItem dato OrderRow
/// </summary>
@@ -1784,6 +1784,45 @@ namespace EgwCoreLib.Lux.Data.Services
return fatto;
}
/// <summary>
/// Creazione record Batch x intestare gli ODL
/// </summary>
/// <param name="newRec"></param>
/// <returns></returns>
public async Task<ProductionBatchModel?> ProductionBatchCreateAsync(ProductionBatchModel newRec)
{
Stopwatch sw = new Stopwatch();
sw.Start();
// calcolo
var dbResult = await dbController.ProductionBatchCreateAsync(newRec);
// svuoto cache...
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:Batch:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:ODL:*");
sw.Stop();
Log.Debug($"ProductionBatchCreateAsync in {sw.Elapsed.TotalMilliseconds} ms");
return dbResult;
}
/// <summary>
/// Insert sul DB di un elenco ODL con calcolo della relativa KEY a cui poter, successivamente, collegare i record child (items)
/// </summary>
/// <param name="listOdl2ins"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task<List<ProductionODLModel>> ProductionOdlCreateAsync(List<ProductionODLModel> listOdl2ins)
{
Stopwatch sw = new Stopwatch();
sw.Start();
// calcolo
var dbResult = await dbController.ProductionOdlCreateAsync(listOdl2ins);
// svuoto cache...
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:ODL:*");
sw.Stop();
Log.Debug($"ProductionOdlCreateAsync in {sw.Elapsed.TotalMilliseconds} ms");
return dbResult;
}
/// <summary>
/// Elenco completo Fasi
/// </summary>
@@ -2011,6 +2050,29 @@ namespace EgwCoreLib.Lux.Data.Services
return fatto;
}
/// <summary>
/// Esegue assegnazione bulk dei ProdItem ad un unico ProdBatch parent (per ora totale x RigaOrd)
/// </summary>
/// <param name="OrderRowId"></param>
/// <param name="ProdBatchId"></param>
/// <returns></returns>
public async Task<int> ProdItemBulkAssignProdBatch(int OrderRowId, int ProdBatchId)
{
Stopwatch sw = new Stopwatch();
sw.Start();
// calcolo
int fatto = await dbController.ProdItemBulkAssignProdBatch(OrderRowId, ProdBatchId);
// svuoto cache...
//await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:ProdItems:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:ProdItems:OrdRowId:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:ProdGroup:OrdRowId:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OrderRows:*");
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OrderRowsByState:*");
sw.Stop();
Log.Debug($"ProdItemBulkAssignProdBatch in {sw.Elapsed.TotalMilliseconds} ms");
return fatto;
}
/// <summary>
/// Elenco dei ProductionItem collegati ad una riga d'ordine
/// </summary>
@@ -10,6 +10,7 @@ NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'Ritorna il prossimo valore di contatore per il flusso richiesto con upsert'
BEGIN
DECLARE vOld INT;
@@ -21,13 +22,12 @@ BEGIN
IF vOld IS NULL THEN
-- Primo valore
SET vOld = 0;
SET vOld = 1;
INSERT INTO utils_counter (RefYear, CountName, Counter)
VALUES (pYear, pName, 1)
VALUES (pYear, pName, vOld)
ON DUPLICATE KEY UPDATE Counter = VALUES(Counter);
SET pValue = 1;
ELSE
-- Incremento
SET vOld = vOld + 1;
@@ -36,6 +36,6 @@ BEGIN
SET Counter = vOld
WHERE RefYear = pYear AND CountName = pName;
SET pValue = vOld;
END IF;
END;
SET pValue = vOld;
END
+1 -1
View File
@@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>0.9.2601.1919</Version>
<Version>0.9.2601.2110</Version>
</PropertyGroup>
<ItemGroup>
@@ -1,122 +1,158 @@
@using EgwCoreLib.Lux.Data.DbModel.Production
<table class="table table-sm table-striped shadow">
<thead>
<tr class="">
<th></th>
<th class="text-center">#</th>
<th class="text-start">Ord</th>
<th class="text-start">Macchina</th>
<th class="text-end" title="Bar"><i class="fa-solid fa-bars-staggered"></i></th>
<th class="text-end" title="Parts"><i class="fa-solid fa-folder-tree"></i></th>
<th class="text-end" title="Time"><i class="fa-solid fa-clock"></i></th>
<th class="text-end">Tot.Time</th>
</tr>
</thead>
<tbody>
@if (DictGrouped != null && DictGrouped.Count > 0)
{
int idx = 1;
foreach (var item in DictGrouped)
{
<tr>
<td class="text-start">
<button class="btn btn-danger" @onclick="() => RemOrder(item.Key)"><i class="fa-solid fa-angles-left"></i> Rem</button>
</td>
<td class="text-center">
<button><i class="fa-solid fa-caret-up"></i></button>
@(idx++)
<button><i class="fa-solid fa-caret-down"></i></button>
</td>
<td class="text-start fs-4">
@item.Key
</td>
<td class="text-start">
@foreach (var detail in item.Value)
{
<div class="px-0">
@detail.PlantListJoin
</div>
}
</td>
<td class="text-end">
@foreach (var detail in item.Value)
{
<div class="px-0">
@detail.BarQty
</div>
}
</td>
<td class="text-end">
@foreach (var detail in item.Value)
{
<div class="px-0">
@detail.NumParts
</div>
}
</td>
<td class="text-end">
@foreach (var detail in item.Value)
{
<div class="px-0">
@FormatEstTime(detail.TotalEstimTime)
</div>
}
</td>
<td class="text-end fs-3">
<b>@FormatEstTime(item.Value.Sum(x => x.TotalEstimTime))</b>
</td>
</tr>
}
}
</tbody>
<tfoot class="table-dark text-light">
<tr class="fw-bold">
<td colspan="3"></td>
@if (ListBalancedDet != null)
{
<td class="text-start">
@foreach (var item in ListBalancedDet)
{
<div class="px-0">
@item.MachineName
</div>
}
</td>
<td class="text-end">
@foreach (var item in ListBalancedDet)
{
<div class="px-0">
@item.TotalBarQty
</div>
}
</td>
<td class="text-end">
@foreach (var item in ListBalancedDet)
{
<div class="px-0">
@item.TotalNumPart
</div>
}
</td>
<td class="text-end">
@foreach (var item in ListBalancedDet)
{
<div class="px-0">
@FormatEstTime(item.TotalTime)
</div>
}
</td>
}
else
{
<td colspan="4"></td>
}
<td class="text-end fs-3">
<b>@FormatEstTime(BalancedTotalTime)</b>
</td>
</tr>
</tfoot>
</table>
<div class="card shadow">
<div class="card-body">
<table class="table table-sm table-striped">
<thead>
<tr class="">
<th></th>
<th class="text-center">#</th>
<th class="text-start">Ord</th>
<th class="text-start">Macchina</th>
<th class="text-end" title="Bar"><i class="fa-solid fa-bars-staggered"></i></th>
<th class="text-end" title="Parts"><i class="fa-solid fa-folder-tree"></i></th>
<th class="text-end" title="Time"><i class="fa-solid fa-clock"></i></th>
<th class="text-end">Tot.Time</th>
</tr>
</thead>
<tbody>
@if (DictGrouped != null && DictGrouped.Count > 0)
{
int idx = 1;
foreach (var item in DictGrouped)
{
<tr>
<td class="text-start">
<button class="btn btn-danger" @onclick="() => RemOrder(item.Key)"><i class="fa-solid fa-angles-left"></i> Rem</button>
</td>
<td class="text-center">
<button><i class="fa-solid fa-caret-up"></i></button>
@(idx++)
<button><i class="fa-solid fa-caret-down"></i></button>
</td>
<td class="text-start fs-4">
@item.Key
</td>
<td class="text-start">
@foreach (var detail in item.Value)
{
<div class="px-0">
@detail.PlantListJoin
</div>
}
</td>
<td class="text-end">
@foreach (var detail in item.Value)
{
<div class="px-0">
@detail.BarQty
</div>
}
</td>
<td class="text-end">
@foreach (var detail in item.Value)
{
<div class="px-0">
@detail.NumParts
</div>
}
</td>
<td class="text-end">
@foreach (var detail in item.Value)
{
<div class="px-0">
@FormatEstTime(detail.TotalEstimTime)
</div>
}
</td>
<td class="text-end fs-3">
<b>@FormatEstTime(item.Value.Sum(x => x.TotalEstimTime))</b>
</td>
</tr>
}
}
</tbody>
<tfoot class="table-dark text-light">
<tr class="fw-bold">
<td colspan="3" class="text-center">
<button class="btn btn-lg @CssToggleBatch" @onclick="ToggleCreaBatch">
@if (ShowCreateBatch)
{
<i class="fa-solid fa-chevron-up"></i> <span class="px-1">Nascondi Crea Commessa</span>
}
else
{
<i class="fa-solid fa-chevron-down"></i> <span class="px-1">Mostra Crea Commessa</span>
}
</button>
</td>
@if (ListBalancedDet != null)
{
<td class="text-start">
@foreach (var item in ListBalancedDet)
{
<div class="px-0">
@item.MachineName
</div>
}
</td>
<td class="text-end">
@foreach (var item in ListBalancedDet)
{
<div class="px-0">
@item.TotalBarQty
</div>
}
</td>
<td class="text-end">
@foreach (var item in ListBalancedDet)
{
<div class="px-0">
@item.TotalNumPart
</div>
}
</td>
<td class="text-end">
@foreach (var item in ListBalancedDet)
{
<div class="px-0">
@FormatEstTime(item.TotalTime)
</div>
}
</td>
}
else
{
<td colspan="4"></td>
}
<td class="text-end fs-3">
<b>@FormatEstTime(BalancedTotalTime)</b>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
@if (ShowCreateBatch && newBatch != null)
{
<div class="card shadow">
<div class="card-body">
<div class="row">
<div class="col-6">
<label class="form-label small">Descrizione Commessa</label>
<input type="text" class="form-control" placeholder="Nome / Descrizione commessa" @bind="newBatch.Description">
</div>
<div class="col-3">
<label class="form-label small">Scadenza Commessa</label>
<input type="datetime-local" class="form-control" @bind="newBatch.DueDate">
</div>
<div class="col-3">
<button class="btn btn-lg btn-success" @onclick="CreateAllComm">
<i class="fa-solid fa-lock"></i> <span class="px-2">Crea Commesse</span> <i class="fa-solid fa-chart-gantt"></i>
</button>
</div>
</div>
</div>
</div>
}
@@ -1,5 +1,7 @@
using EgwCoreLib.Lux.Core.Generic;
using EgwCoreLib.Lux.Data.DbModel.Production;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace Lux.UI.Components.Compo.Planner
{
@@ -13,14 +15,12 @@ namespace Lux.UI.Components.Compo.Planner
[Parameter]
public EventCallback<int> EC_RemBalance { get; set; }
[Parameter]
public EventCallback<BatchCreateInfo> EC_ReqCreateBatch { get; set; }
#endregion Public Properties
#region Protected Properties
protected decimal BalancedTotalTime
{
get => AllRecords?.Sum(x => x.TotalEstimTime) ?? 0;
}
#region Public Methods
/// <summary>
/// Richiede rimozione da balance dell' OrderRow UID selezionato
@@ -45,6 +45,39 @@ namespace Lux.UI.Components.Compo.Planner
}
}
/// <summary>
/// Struttura ritorno x creazione Batch e ODL
/// </summary>
public class BatchCreateInfo
{
/// <summary>
/// Info batch da creare
/// </summary>
public ProductionBatchModel NewBatch { get; set; } = null!;
/// <summary>
/// Dettaglio macchine x cui creare ODL
/// </summary>
public List<GroupDetailDTO> GroupDetail { get; set; } = null!;
/// <summary>
/// Record di partenza x esecuzione creazione ODL
/// </summary>
public List<ProductionGroupModel> AllRecords { get; set; } = null!;
}
#endregion Public Methods
#region Protected Properties
protected decimal BalancedTotalTime
{
get => AllRecords?.Sum(x => x.TotalEstimTime) ?? 0;
}
[Inject]
protected IJSRuntime JSRuntime { get; set; } = null!;
#endregion Protected Properties
#region Protected Methods
@@ -71,45 +104,92 @@ namespace Lux.UI.Components.Compo.Planner
ListBalancedDet = AllRecords?
.SelectMany(pg => pg.WorkGroupList) // appiattisce tutti i dizionari
.GroupBy(kvp => kvp.Key) // raggruppa per la chiave del dizionario
.Select(g => new GroupDetail
.Select(g =>
{
MachineName = g.Key,
TotalBarQty = g.Sum(x => x.Value.BarQty),
TotalNumPart = g.Sum(x => x.Value.NumParts),
TotalTime = g.Sum(x => x.Value.Time)
// Materializziamo i tag separatamente per sicurezza
List<string> tags = g.SelectMany(x => x.Value.TagList ?? new List<string>()).ToList();
// genero oggetto DTO in return
return new GroupDetailDTO
{
MachineName = g.Key,
TagList = tags,
TotalBarQty = g.Sum(x => x.Value.BarQty),
TotalNumPart = g.Sum(x => x.Value.NumParts),
TotalTime = g.Sum(x => x.Value.Time)
};
})
.ToList();
}
}
protected void ToggleCreaBatch()
{
ShowCreateBatch = !ShowCreateBatch;
if (ShowCreateBatch)
{
newBatch = new ProductionBatchModel()
{
Description = $"Nuova Commessa {DateTime.Now:yyyy-MM-dd_HH:mm:ss}",
DueDate = DateTime.Today.AddMonths(3),
};
}
else
{
newBatch = null;
}
}
#endregion Protected Methods
#region Private Fields
private Dictionary<string, List<ProductionGroupModel>> DictGrouped = new();
private ProductionBatchModel? newBatch = null;
private bool ShowCreateBatch = false;
#endregion Private Fields
#region Protected Classes
protected class GroupDetail
{
#region Public Properties
public string MachineName { get; set; } = "";
public int TotalBarQty { get; set; } = 0;
public int TotalNumPart { get; set; } = 0;
public decimal TotalTime { get; set; } = 0;
#endregion Public Properties
}
#endregion Protected Classes
#region Private Properties
private List<GroupDetail>? ListBalancedDet { get; set; } = new();
private string CssToggleBatch
{
get => ShowCreateBatch ? "btn-warning" : "btn-success";
}
private List<GroupDetailDTO>? ListBalancedDet { get; set; } = new();
#endregion Private Properties
#region Private Methods
private async Task CreateAllComm(Microsoft.AspNetCore.Components.Web.MouseEventArgs args)
{
if (ListBalancedDet != null && newBatch!=null && AllRecords!=null)
{
var numMacc = ListBalancedDet.Count;
var totBars = ListBalancedDet.Sum(x => x.TotalBarQty);
var totNumPart = ListBalancedDet.Sum(x => x.TotalNumPart);
if (!await JSRuntime.InvokeAsync<bool>("confirm", $"Sicuro di voler creare la commessa su ogni impianto?{Environment.NewLine}L'impegno totale è per:" +
$"{Environment.NewLine} - macchine: {numMacc}" +
$"{Environment.NewLine} - parti: {totNumPart}" +
$"{Environment.NewLine} - barre: {totBars}" +
$"{Environment.NewLine} - tempo lavorazioni: {FormatEstTime(BalancedTotalTime)}"))
return;
BatchCreateInfo newData = new BatchCreateInfo()
{
AllRecords = AllRecords,
NewBatch = newBatch,
GroupDetail = ListBalancedDet
};
// invia info x richiesta creazione batch.
await EC_ReqCreateBatch.InvokeAsync(newData);
}
}
#endregion Private Methods
}
}
@@ -22,7 +22,7 @@
}
else
{
<BalanceProgGroup AllRecords="@ListBalancedRecords" EC_RemBalance="RemoveBalance"></BalanceProgGroup>
<BalanceProgGroup AllRecords="@ListBalancedRecords" EC_RemBalance="RemoveBalance" EC_ReqCreateBatch="CreateBatch"></BalanceProgGroup>
}
</div>
</div>
@@ -11,6 +11,7 @@ using Newtonsoft.Json;
using System.Diagnostics.Eventing.Reader;
using System.Threading.Tasks;
using static EgwCoreLib.Lux.Core.Enums;
using static Lux.UI.Components.Compo.Planner.BalanceProgGroup;
namespace Lux.UI.Components.Pages
{
@@ -73,6 +74,63 @@ namespace Lux.UI.Components.Pages
#region Private Methods
/// <summary>
/// Creazione progetti da schedulare...
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private async Task CreateBatch(BatchCreateInfo batchData)
{
// per prima cosa creo il batch...
var recBatch = await DLService.ProductionBatchCreateAsync(batchData.NewBatch);
// se ok batch...
if (recBatch != null)
{
List<ProductionODLModel> listOdl = new List<ProductionODLModel>();
// uso una Tupla
var dictParts = new Dictionary<(int phaseId, int resId, string machine, int index), List<string>>();
// ciclo x ogni macchina...
foreach (var item in batchData.GroupDetail)
{
// dovrei recuperare Ciclo, Articolo, Fasi e Risorse dalle macchine ... x ora ND/ND/0/0
int phaseId = 0;
int resId = 0;
int idx = 10; // fisso come fase/res
// preparo la lista degli ODL
var newOdl = new ProductionODLModel()
{
ProdBatchID = recBatch.ProdBatchID,
ProdPlantCod = item.MachineName,
Index = idx,
PhaseID = phaseId,
ResourceID = resId,
Description = $"Ciclo ND | Art: ND | Fase: {phaseId} | Res: {resId}",
EstimTime = item.TotalTime,
Qty = item.TotalNumPart
};
listOdl.Add(newOdl);
// costruisco il dizionario delle parts che mi servirà poi ad associare gli items
dictParts[(phaseId, resId, item.MachineName, idx)] = item.TagList;
}
// se ho record li scrivo!
if (listOdl.Count > 0)
{
// creazione ODL
List<ProductionODLModel> dbList = await DLService.ProductionOdlCreateAsync(listOdl);
// fix items sul batch ID, ciclo sui prodGroup
int numParts = 0;
foreach (var item in batchData.AllRecords)
{
numParts += await DLService.ProdItemBulkAssignProdBatch(item.OrderRowID, recBatch.ProdBatchID);
}
// ora lavoro sugli items x collegarli agli ODL... parto dal dizionario e cerco nell'elenco degli ODL creati...
}
}
}
private async Task DoBalance(int OrderRowID)
{
if (!await JSRuntime.InvokeAsync<bool>("confirm", $"Sicuro di voler Bilanciare la riga d'ordine?"))
@@ -107,6 +165,18 @@ namespace Lux.UI.Components.Pages
}
}
/// <summary>
/// Formattazione oraria impegno
/// </summary>
/// <param name="totSeconds"></param>
/// <returns></returns>
private string FormatEstTime(decimal totSeconds)
{
var tSpan = TimeSpan.FromSeconds((double)totSeconds);
string answ = EgwCoreLib.Lux.Core.DtUtils.FormatDateTime(tSpan);
return answ;
}
/// <summary>
/// Ricezione update prod --> rileggo i dati!
/// </summary>
+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>0.9.2601.1919</Version>
<Version>0.9.2601.2110</Version>
</PropertyGroup>
<ItemGroup>
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>LUX - Web Windows MES</i>
<h4>Versione: 0.9.2601.1919</h4>
<h4>Versione: 0.9.2601.2110</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
0.9.2601.1919
0.9.2601.2110
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>0.9.2601.1919</version>
<version>0.9.2601.2110</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>