using AppData;
using AppData.DS_AppTableAdapters;
using NKC_SDK;
using SteamWare;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace NKC_WF.WebUserControls
{
public partial class cmp_batchDetailSplit : BaseUserControl, IDisposable
{
#region Public Properties
public int BatchId
{
set
{
hfBatchId.Value = value.ToString();
if (BatchId > 0)
{
checkCreateDescendant();
doUpdate(true);
}
fixRatio();
}
get
{
int answ = 0;
int.TryParse(hfBatchId.Value, out answ);
return answ;
}
}
public bool enabIsChanged
{
get => codEnabled != codEnabledPrev;
}
///
/// Abilitazione azioni button-based
///
public bool BtnEnabled
{
get
{
return chkActEnab.Checked;
}
set
{
chkActEnab.Checked = value;
}
}
public bool isSplitted
{
get
{
bool answ = false;
bool.TryParse(hfIsSplit.Value, out answ);
return answ;
}
set
{
hfIsSplit.Value = $"{value}";
}
}
#endregion Public Properties
#region Public Methods
public override void Dispose()
{
cmp_orderExtListNE01.eh_doRefresh -= Cmp_orderExtListNE01_eh_doRefresh;
cmp_orderExtListNE02.eh_doRefresh -= Cmp_orderExtListNE02_eh_doRefresh;
cmp_orderExtListNE03.eh_doRefresh -= Cmp_orderExtListNE03_eh_doRefresh;
base.Dispose();
}
public void doUpdate(bool doReset)
{
fixChildBatch();
fixRatio();
checkDisplayMode();
fixEnabled();
if (doReset)
{
raiseReset();
}
}
#endregion Public Methods
#region Protected Fields
protected double Ratio01 = 0;
protected double Ratio02 = 0;
protected double Ratio03 = 0;
#endregion Protected Fields
#region Protected Properties
protected bool BatchIsAncestor
{
get
{
return ComLib.BType(BatchId) == BatchType.Ancestor;
}
}
///
/// Status corrente del batch
///
protected BatchStatus CurrBatchStatus
{
get
{
return ComLib.BStatus(BatchId);
}
}
protected double fullTime
{
get
{
double answ = 1;
if (!string.IsNullOrEmpty(hfFullTime.Value))
{
double.TryParse(hfFullTime.Value, out answ);
}
return answ;
}
set
{
hfFullTime.Value = $"{value}";
}
}
protected int numKitBatchAncestor
{
get
{
int answ = 0;
if (BatchIsAncestor)
{
DS_App.KitListDataTable tabNeVirt = ComLib.KitListByBatch(BatchId);
answ = tabNeVirt.Count();
}
return answ;
}
}
protected int numOrd01
{
get
{
int answ = 0;
DS_App.OrderListTreeDataTable tabNe01 = ComLib.OrdersExtByBatch(cmp_orderExtListNE01.BatchId);
answ = tabNe01.Count();
return answ;
}
}
protected int numOrd02
{
get
{
int answ = 0;
DS_App.OrderListTreeDataTable tabNe02 = ComLib.OrdersExtByBatch(cmp_orderExtListNE02.BatchId);
answ = tabNe02.Count();
return answ;
}
}
protected int numOrd03
{
get
{
int answ = 0;
DS_App.OrderListTreeDataTable tabNe03 = ComLib.OrdersExtByBatch(cmp_orderExtListNE03.BatchId);
answ = tabNe03.Count();
return answ;
}
}
protected int numOrdBatchAncestor
{
get
{
int answ = 0;
if (BatchIsAncestor)
{
DS_App.OrderListTreeDataTable tabNeVirt = ComLib.OrdersExtByBatch(BatchId);
answ = tabNeVirt.Count();
}
return answ;
}
}
///
/// Tabella dei batch Descendant di quello corrente
///
protected DS_App.BatchListDataTable TabBatchDesc
{
get
{
return ComLib.BatchDescendant(BatchId);
}
}
protected DS_App.OrderListTreeDataTable TabOrders
{
get
{
// cerco in redis
return ComLib.OrdersExtByBatchTree(BatchId);
}
}
protected double totTime01
{
get
{
double answ = 0;
DS_App.OrderListTreeDataTable tabNe01 = ComLib.OrdersExtByBatch(cmp_orderExtListNE01.BatchId);
answ = tabNe01.Sum(x => x.EstProcTime);
return answ;
}
}
protected double totTime02
{
get
{
double answ = 0;
DS_App.OrderListTreeDataTable tabNe02 = ComLib.OrdersExtByBatch(cmp_orderExtListNE02.BatchId);
answ = tabNe02.Sum(x => x.EstProcTime);
return answ;
}
}
protected double totTime03
{
get
{
double answ = 0;
DS_App.OrderListTreeDataTable tabNe03 = ComLib.OrdersExtByBatch(cmp_orderExtListNE03.BatchId);
answ = tabNe03.Sum(x => x.EstProcTime);
return answ;
}
}
#endregion Protected Properties
#region Protected Methods
///
/// Cerca il set con lo score migliore calcolando x subset della lista ordinata
///
/// Lista ordinata oggetti (INT) + valore
/// Valore desiderato (come SOMMA)
/// Massima profondità ricorsione accettata (x evitare loop infinito)
///
protected Dictionary findLocalMin(Dictionary OrderedList, double TargetVal, int maxDepth)
{
Dictionary answ = new Dictionary();
List Candidates = new List();
OrderSetSim CurrSimSet = new OrderSetSim();
// parte dal valore (singolo) più piccolo tra quelli maggiori del target... se c'è...
var OrdSup = OrderedList.Where(x => x.Value > TargetVal).OrderBy(x => x.Value);
if (OrdSup != null && OrdSup.Any())
{
var currOrder = OrdSup.FirstOrDefault();
CurrSimSet = new OrderSetSim();
CurrSimSet.TargetValue = TargetVal;
CurrSimSet.OrderSet.Add(currOrder.Key, currOrder.Value);
Candidates.Add(CurrSimSet);
}
// ora guardo gli elementi restanti.. se ci sono
var OrdInf = OrderedList.Where(x => x.Value <= TargetVal).OrderByDescending(x => x.Value).ToDictionary(t => t.Key, t => t.Value);
if (OrdInf != null && OrdInf.Any())
{
var currOrder = OrdInf.FirstOrDefault();
CurrSimSet = new OrderSetSim();
CurrSimSet.TargetValue = TargetVal;
CurrSimSet.OrderSet.Add(currOrder.Key, currOrder.Value);
Candidates.Add(CurrSimSet);
// prendo i restanti tranne il primo
OrdInf.Remove(currOrder.Key);
// guardo i successivi che NON superano + corrente...
Dictionary TestOrderSetMinDelta = findStepMin(OrdInf, TargetVal - currOrder.Value);
TestOrderSetMinDelta.Add(currOrder.Key, currOrder.Value);
// verifico se migliorativo...
if (TestOrderSetMinDelta.Count > 0)
{
OrderSetSim CurrSet = new OrderSetSim();
CurrSet.TargetValue = TargetVal;// - currOrder.Value;
CurrSet.OrderSet = TestOrderSetMinDelta;
Candidates.Add(CurrSet);
}
// solo successivi che non superano
Dictionary TestOrderSetMin = findStepMin(OrdInf, TargetVal);
// verifico se migliorativo...
if (TestOrderSetMin.Count > 0)
{
OrderSetSim CurrSet = new OrderSetSim();
CurrSet.TargetValue = TargetVal;// - currOrder.Value;
CurrSet.OrderSet = TestOrderSetMin;
Candidates.Add(CurrSet);
}
// se posso fare ricorsioni
if (maxDepth > 0)
{
maxDepth--;
// se rimane qualcosa...
if (OrdInf != null && OrdInf.Any())
{
// calcolo il minimo locale nei 2 casi, da soli
Dictionary TestOrderSet01 = findLocalMin(OrdInf, TargetVal, maxDepth);
if (TestOrderSet01.Count > 0)
{
OrderSetSim CurrSet = new OrderSetSim();
CurrSet.TargetValue = TargetVal;
CurrSet.OrderSet = TestOrderSet01;
Candidates.Add(CurrSet);
}
// ...e con il primo valore...
Dictionary TestOrderSet02 = findLocalMin(OrdInf, TargetVal - currOrder.Value, maxDepth);
TestOrderSet02.Add(currOrder.Key, currOrder.Value);
// verifico se migliorativo...
if (TestOrderSet02.Count > 0)
{
OrderSetSim CurrSet = new OrderSetSim();
CurrSet.TargetValue = TargetVal - currOrder.Value;
CurrSet.OrderSet = TestOrderSet02;
Candidates.Add(CurrSet);
}
}
}
}
// cerco il minimo...
if (Candidates != null && Candidates.Count > 0)
{
answ = Candidates.OrderBy(x => x.IndexScore).FirstOrDefault().OrderSet;
}
// calcolo il minimo e lo restituisco...
return answ;
}
/// Cerca il set della lista ordinata <= target val Lista ordinata oggetti (INT) + valore Valore desiderato (come SOMMA)
protected Dictionary findStepMin(Dictionary OrderedList, double TargetVal)
{
double CurrVal = 0;
Dictionary answ = new Dictionary();
foreach (var item in OrderedList)
{
if (item.Value <= (TargetVal - CurrVal))
{
CurrVal += item.Value;
answ.Add(item.Key, item.Value);
}
}
// restituisco set minore...
return answ;
}
protected void lbtBalance_Click(object sender, EventArgs e)
{
divError.Visible = false;
codEnabledPrev = codEnabled;
lblWarnChange.Visible = enabIsChanged;
// imposto la % secondo numero di abilitati...
Ratio01 = enable01 ? (double)(100 / numEnabled) / 100 : 0;
Ratio02 = enable02 ? (double)(100 / numEnabled) / 100 : 0;
Ratio03 = enable03 ? (double)(100 / numEnabled) / 100 : 0;
Log.Instance.Info($"Rebalance requested (click) | numEnabled: {numEnabled} | R01: {Ratio01:P1} | R02: {Ratio02:P1} | R03: {Ratio03:P1}");
bool fatto = RebalanceOrder();
// 2024.12.13 eseguo riassegnazione kit a macchine come OLT...
if (BatchIsAncestor)
{
// effettuo VERA ri-assegnazione ordini/kit a nuovi batch
DLMan.taOLT.setBatchSplit(BatchId, true);
}
// svuoto cache redis per i calcoli...
ComLib.OrdersExtResetCache();
doUpdate(true);
lbtBalance.Focus();
string message = fatto ? "Balance done" : "Balance task error!";
Log.Instance.Info(message);
}
///
/// Sposta l'ordine + piccolo dalla macchina selezionata dal command argument nell'altra attiva
///
///
///
protected void lbtOrdAdd_Click(object sender, EventArgs e)
{
string CodMac = ((LinkButton)sender).CommandArgument;
moveOrderByCodMac(CodMac, true);
codEnabledPrev = codEnabled;
lblWarnChange.Visible = enabIsChanged;
}
///
/// Sposta TUTTI gli ordini nalla macchina selezionata nell'altra attiva
///
///
///
protected void lbtOrdAddAll_Click(object sender, EventArgs e)
{
string CodMac = ((LinkButton)sender).CommandArgument;
moveAllOrderFromMac(CodMac, true);
codEnabledPrev = codEnabled;
lblWarnChange.Visible = enabIsChanged;
}
///
/// Sposta l'ordine + piccolo dalla macchina selezionata dal command argument nell'altra attiva
///
///
///
protected void lbtOrdRem_Click(object sender, EventArgs e)
{
string CodMac = ((LinkButton)sender).CommandArgument;
moveOrderByCodMac(CodMac, false);
codEnabledPrev = codEnabled;
lblWarnChange.Visible = enabIsChanged;
}
///
/// Sposta TUTTI gli ordini dalla macchina selezionata nell'altra attiva
///
///
///
protected void lbtOrdRemAll_Click(object sender, EventArgs e)
{
string CodMac = ((LinkButton)sender).CommandArgument;
moveAllOrderFromMac(CodMac, false);
codEnabledPrev = codEnabled;
lblWarnChange.Visible = enabIsChanged;
}
protected void lbtToggle01_Click(object sender, EventArgs e)
{
// controllo che ce ne sia ALMENO un altro attivo
if (enable01 && numEnabled > 1 || !enable01)
{
enable01 = !enable01;
checkDisplayMode();
fixEnabled();
}
lbtToggle01.Focus();
}
protected void lbtToggle02_Click(object sender, EventArgs e)
{
// controllo che ce ne sia ALMENO un altro attivo
if (enable02 && numEnabled > 1 || !enable02)
{
enable02 = !enable02;
checkDisplayMode();
fixEnabled();
}
lbtToggle02.Focus();
}
protected void lbtToggle03_Click(object sender, EventArgs e)
{
// controllo che ce ne sia ALMENO un altro attivo
if (enable03 && numEnabled > 1 || !enable03)
{
enable03 = !enable03;
checkDisplayMode();
fixEnabled();
}
lbtToggle03.Focus();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// verifica visualizzazione
toggleAll(true);
codEnabledPrev = codEnabled;
fixChildBatch();
fixRatio();
checkDisplayMode();
fixEnabled();
divError.Visible = false;
// 2024.12.13: controllo che NON ci siano ordini o kit sul batch ancestor
lblSplitRequest.Visible = (numKitBatchAncestor + numOrdBatchAncestor) > 0;
}
cmp_orderExtListNE01.eh_doRefresh += Cmp_orderExtListNE01_eh_doRefresh;
cmp_orderExtListNE02.eh_doRefresh += Cmp_orderExtListNE02_eh_doRefresh;
cmp_orderExtListNE03.eh_doRefresh += Cmp_orderExtListNE03_eh_doRefresh;
}
#endregion Protected Methods
#region Private Properties
private int codEnabled
{
get
{
int answ = 0;
answ += enable01 ? 100 : 0;
answ += enable02 ? 10 : 0;
answ += enable03 ? 1 : 0;
return answ;
}
}
private int codEnabledPrev
{
get
{
int answ = 0;
int.TryParse(hfCodEnabPrev.Value, out answ);
return answ;
}
set
{
hfCodEnabPrev.Value = $"{value}";
}
}
private bool enable01
{
get
{
bool answ = true;
bool.TryParse(hfEnabled01.Value, out answ);
return answ;
}
set
{
hfEnabled01.Value = $"{value}";
}
}
private bool enable02
{
get
{
bool answ = false;
bool.TryParse(hfEnabled02.Value, out answ);
return answ;
}
set
{
hfEnabled02.Value = $"{value}";
}
}
private bool enable03
{
get
{
bool answ = false;
bool.TryParse(hfEnabled03.Value, out answ);
return answ;
}
set
{
hfEnabled03.Value = $"{value}";
}
}
private bool movEnabled
{
get
{
return numEnabled == 2;
}
}
private int numEnabled
{
get
{
int answ = 0;
answ += enable01 ? 1 : 0;
answ += enable02 ? 1 : 0;
answ += enable03 ? 1 : 0;
return answ;
}
}
#endregion Private Properties
#region Private Methods
private void checkCreateDescendant()
{
// se ho un batchId...
if (BatchId != 0)
{
// verifico se ho descendant
if (TabBatchDesc.Rows.Count == 0)
{
// altrimenti creo...
DLMan.taBL.makeDescendantByKey(BatchId, PlaceCod);
}
}
}
///
/// verifico modalità display (editing solo se PRIMA di lanciare nesting...)
///
private void checkDisplayMode()
{
var splitEnab = BtnEnabled && (BatchIsAncestor && CurrBatchStatus <= BatchStatus.EstimationDone && numEnabled > 0);
// se non suddiviso --> indico rosso!
double tmpTime = totTime01 + totTime02 + totTime03;
string baseCssClass = "btn btn-success btn-block";
if (tmpTime < 0.1)
{
// imposto colore btn ROSSO...
baseCssClass = "btn btn-danger btn-block";
isSplitted = false;
}
else
{
isSplitted = true;
}
lbtBalance.CssClass = splitEnab ? baseCssClass : baseCssClass + " disabled";
cmp_orderExtListNE01.Visible = splitEnab;
cmp_orderExtListNE02.Visible = splitEnab;
cmp_orderExtListNE03.Visible = splitEnab;
cmp_batchDetailSplitInfoNE01.Visible = !splitEnab;
cmp_batchDetailSplitInfoNE02.Visible = !splitEnab;
cmp_batchDetailSplitInfoNE03.Visible = !splitEnab;
// controlo il batch sia ancestor e NON abbia ordini associati...
if (BatchIsAncestor)
{
// 2024.12.13: controllo che NON ci siano ordini o kit sul batch ancestor
bool hasErrors = (numKitBatchAncestor + numOrdBatchAncestor) > 0;
lblSplitRequest.Visible = hasErrors;
if (hasErrors)
{
lbtBalance.CssClass = "btn btn-danger btn-block";
isSplitted = false;
}
}
}
private void Cmp_orderExtListNE01_eh_doRefresh(object sender, EventArgs e)
{
// sposto ordine in altro set, calcolandolo
int batchId = enable02 ? cmp_orderExtListNE02.BatchId : cmp_orderExtListNE03.BatchId;
int origBatchId = cmp_orderExtListNE01.BatchId;
int origOrdId = cmp_orderExtListNE01.SelOrderId;
moveOrderById(batchId, origBatchId, origOrdId);
}
private void Cmp_orderExtListNE02_eh_doRefresh(object sender, EventArgs e)
{
// sposto ordine in altro set, calcolandolo
int batchId = enable01 ? cmp_orderExtListNE01.BatchId : cmp_orderExtListNE03.BatchId;
int origBatchId = cmp_orderExtListNE02.BatchId;
int origOrdId = cmp_orderExtListNE02.SelOrderId;
moveOrderById(batchId, origBatchId, origOrdId);
}
private void Cmp_orderExtListNE03_eh_doRefresh(object sender, EventArgs e)
{
// sposto ordine in altro set, calcolandolo
int batchId = enable01 ? cmp_orderExtListNE01.BatchId : cmp_orderExtListNE02.BatchId;
int origBatchId = cmp_orderExtListNE03.BatchId;
int origOrdId = cmp_orderExtListNE03.SelOrderId;
moveOrderById(batchId, origBatchId, origOrdId);
}
private void fixChildBatch()
{
// sistemo dati ordini
DS_App.BatchListDataTable TabBatch = TabBatchDesc;
if (TabBatch != null && TabBatch.Count > 0)
{
cmp_orderExtListNE01.BatchId = TabBatch.Rows.Count > 0 ? TabBatch[0].BatchID : 0;
cmp_orderExtListNE02.BatchId = TabBatch.Rows.Count > 1 ? TabBatch[1].BatchID : 0;
cmp_orderExtListNE03.BatchId = TabBatch.Rows.Count > 2 ? TabBatch[2].BatchID : 0;
cmp_orderExtListNE01.doUpdate();
cmp_orderExtListNE02.doUpdate();
cmp_orderExtListNE03.doUpdate();
try
{
cmp_batchDetailSplitInfoNE01.BatchId = cmp_orderExtListNE01.BatchId;
cmp_batchDetailSplitInfoNE02.BatchId = cmp_orderExtListNE02.BatchId;
cmp_batchDetailSplitInfoNE03.BatchId = cmp_orderExtListNE03.BatchId;
}
catch (Exception exc)
{
Log.Instance.Error($"Error during fixChildBatch{Environment.NewLine}{exc}");
}
}
}
private void fixEnabled()
{
lbtToggle01.Enabled = BtnEnabled;
lbtToggle02.Enabled = BtnEnabled;
lbtToggle03.Enabled = BtnEnabled;
lblWarnChange.Visible = enabIsChanged;
string secCss = BtnEnabled ? "btn btn-sm btn-secondary" : "btn btn-sm btn-secondary disabled";
lbtToggle01.CssClass = BtnEnabled && enable01 ? "btn btn-sm btn-primary" : secCss;
lbtToggle02.CssClass = BtnEnabled && enable02 ? "btn btn-sm btn-primary" : secCss;
lbtToggle03.CssClass = BtnEnabled && enable03 ? "btn btn-sm btn-primary" : secCss;
lbtOrdAdd01.CssClass = BtnEnabled && movEnabled && enable01 ? "btn btn-success px-3" : "btn btn-secondary px-3 disabled";
lbtOrdAdd02.CssClass = BtnEnabled && movEnabled && enable02 ? "btn btn-success px-3" : "btn btn-secondary px-3 disabled";
lbtOrdAdd03.CssClass = BtnEnabled && movEnabled && enable03 ? "btn btn-success px-3" : "btn btn-secondary px-3 disabled";
lbtOrdRem01.CssClass = BtnEnabled && movEnabled && enable01 ? "btn btn-danger px-3" : "btn btn-secondary px-3 disabled";
lbtOrdRem02.CssClass = BtnEnabled && movEnabled && enable02 ? "btn btn-danger px-3" : "btn btn-secondary px-3 disabled";
lbtOrdRem03.CssClass = BtnEnabled && movEnabled && enable03 ? "btn btn-danger px-3" : "btn btn-secondary px-3 disabled";
lbtOrdRemAll01.CssClass = BtnEnabled && movEnabled && enable01 ? "btn btn-primary" : "btn btn-secondary disabled";
lbtOrdRemAll02.CssClass = BtnEnabled && movEnabled && enable02 ? "btn btn-primary" : "btn btn-secondary disabled";
lbtOrdRemAll03.CssClass = BtnEnabled && movEnabled && enable03 ? "btn btn-primary" : "btn btn-secondary disabled";
lbtOrdAddAll01.CssClass = BtnEnabled && movEnabled && enable01 ? "btn btn-primary" : "btn btn-secondary disabled";
lbtOrdAddAll02.CssClass = BtnEnabled && movEnabled && enable02 ? "btn btn-primary" : "btn btn-secondary disabled";
lbtOrdAddAll03.CssClass = BtnEnabled && movEnabled && enable03 ? "btn btn-primary" : "btn btn-secondary disabled";
cmp_orderExtListNE01.enableMove = BtnEnabled && enable01 && movEnabled;
cmp_orderExtListNE02.enableMove = BtnEnabled && enable02 && movEnabled;
cmp_orderExtListNE03.enableMove = BtnEnabled && enable03 && movEnabled;
divHeadNe01.Attributes.Remove("class");
divHeadNe02.Attributes.Remove("class");
divHeadNe03.Attributes.Remove("class");
divHeadNe01.Attributes.Add("class", BtnEnabled && enable01 ? "card-header bg-dark text-light py-1" : "card-header py-1");
divHeadNe02.Attributes.Add("class", BtnEnabled && enable02 ? "card-header bg-dark text-light py-1" : "card-header py-1");
divHeadNe03.Attributes.Add("class", BtnEnabled && enable03 ? "card-header bg-dark text-light py-1" : "card-header py-1");
}
private void fixRatio()
{
// calcolo tempi....
double tmpTime = totTime01 + totTime02 + totTime03;
fullTime = tmpTime > 0 ? tmpTime : 1;
// sistemazione ratio calcolate...
Ratio01 = totTime01 / fullTime;
Ratio02 = totTime02 / fullTime;
// ratio 3 è complemento a 100...
Ratio03 = 1 - (Ratio01 + Ratio02);
// sistemo etichette...
lblTime01.Text = $"{totTime01:N1} min";
lblTime02.Text = $"{totTime02:N1} min";
lblTime03.Text = $"{totTime03:N1} min";
lblNumOrd01.Text = $"#{numOrd01} ord";
lblNumOrd02.Text = $"#{numOrd02} ord";
lblNumOrd03.Text = $"#{numOrd03} ord";
// sistemo campi testo...
lblRat01.Text = $"{Ratio01:P1}";
lblRat02.Text = $"{Ratio02:P1}";
lblRat03.Text = $"{Ratio03:P1}";
}
///
/// Spostamento di tutti gli ordini tra batch
///
/// Cod macchina selezionata x azione (orig)
/// True = aggiunge a macchina selezionata, false = toglie
private void moveAllOrderFromMac(string CodMac, bool addOrd)
{
int batchOrigId = 0;
int batchDestId = 0;
DS_App.OrderListTreeRow ord2move = null;
// recupero ordini della macchina
switch (CodMac)
{
case "NE01":
batchOrigId = cmp_orderExtListNE01.BatchId;
batchDestId = enable02 ? cmp_orderExtListNE02.BatchId : cmp_orderExtListNE03.BatchId;
break;
case "NE02":
batchOrigId = cmp_orderExtListNE02.BatchId;
batchDestId = enable01 ? cmp_orderExtListNE01.BatchId : cmp_orderExtListNE03.BatchId;
break;
case "NE03":
batchOrigId = cmp_orderExtListNE03.BatchId;
batchDestId = enable01 ? cmp_orderExtListNE01.BatchId : cmp_orderExtListNE02.BatchId;
break;
default:
break;
}
if (batchOrigId > 0)
{
DS_App.OrderListTreeDataTable tabOLT = new DS_App.OrderListTreeDataTable();
// prendo ordine in base ad add/remove...
if (addOrd)
{
tabOLT = ComLib.OrdersExtByBatch(batchDestId);
}
else
{
// recupero la tab da cui partire in base ad add/remove...
tabOLT = ComLib.OrdersExtByBatch(batchOrigId);
}
// ciclo x tutti gli ordini
foreach (var ordine in tabOLT)
{
// sposto!
if (addOrd)
{
DLMan.taOLT.updateBatch(batchDestId, ordine.OrdID, batchOrigId);
}
else
{
DLMan.taOLT.updateBatch(batchOrigId, ordine.OrdID, batchDestId);
}
}
// 2024.12.13 eseguo riassegnazione kit a macchine come OLT...
if (BatchIsAncestor)
{
// effettuo VERA ri-assegnazione ordini/kit a nuovi batch
DLMan.taOLT.setBatchSplit(BatchId, true);
}
// resetto batch ordini...
ComLib.OrdersExtResetCache();
// ricalcolo
fixChildBatch();
fixRatio();
}
}
///
/// Spostamento ordine tra batch
///
/// Cod macchina selezionata x azione (orig)
/// True = aggiunge a macchina selezionata, false = toglie
private void moveOrderByCodMac(string CodMac, bool addOrd)
{
int batchOrigId = 0;
int batchDestId = 0;
int ordId = 0;
DS_App.OrderListTreeRow ord2move = null;
// recupero ordini della macchina
switch (CodMac)
{
case "NE01":
batchOrigId = cmp_orderExtListNE01.BatchId;
batchDestId = enable02 ? cmp_orderExtListNE02.BatchId : cmp_orderExtListNE03.BatchId;
break;
case "NE02":
batchOrigId = cmp_orderExtListNE02.BatchId;
batchDestId = enable01 ? cmp_orderExtListNE01.BatchId : cmp_orderExtListNE03.BatchId;
break;
case "NE03":
batchOrigId = cmp_orderExtListNE03.BatchId;
batchDestId = enable01 ? cmp_orderExtListNE01.BatchId : cmp_orderExtListNE02.BatchId;
break;
default:
break;
}
if (batchOrigId > 0)
{
DS_App.OrderListTreeDataTable tabOLT = new DS_App.OrderListTreeDataTable();
// prendo ordine in base ad add/remove...
if (addOrd)
{
tabOLT = ComLib.OrdersExtByBatch(batchDestId);
}
else
{
// recupero la tab da cui partire in base ad add/remove...
tabOLT = ComLib.OrdersExtByBatch(batchOrigId);
}
ord2move = tabOLT.OrderBy(x => x.EstProcTime).FirstOrDefault();
if (ord2move != null)
{
ordId = ord2move.OrdID;
}
// sposto!
if (addOrd)
{
DLMan.taOLT.updateBatch(batchDestId, ordId, batchOrigId);
}
else
{
DLMan.taOLT.updateBatch(batchOrigId, ordId, batchDestId);
}
// 2024.12.13 eseguo riassegnazione kit a macchine come OLT...
if (BatchIsAncestor)
{
// effettuo VERA ri-assegnazione ordini/kit a nuovi batch
DLMan.taOLT.setBatchSplit(BatchId, true);
}
codEnabledPrev = codEnabled;
lblWarnChange.Visible = enabIsChanged;
// resetto batch ordini...
ComLib.OrdersExtResetCache();
// ricalcolo
fixChildBatch();
fixRatio();
}
}
///
/// Effettua spostamento ordine passando ID specifici batch src, ordine, batch dest...
///
///
///
///
private void moveOrderById(int batchId, int origBatchId, int origOrdId)
{
DLMan.taOLT.updateBatch(origBatchId, origOrdId, batchId);
// 2024.12.13 eseguo riassegnazione kit a macchine come OLT...
if (BatchIsAncestor)
{
// effettuo VERA ri-assegnazione ordini/kit a nuovi batch
DLMan.taOLT.setBatchSplit(BatchId, true);
}
codEnabledPrev = codEnabled;
lblWarnChange.Visible = enabIsChanged;
// resetto batch ordini...
ComLib.OrdersExtResetCache();
fixChildBatch();
fixRatio();
}
///
/// effettua ribilanciamento ordini partendo da elenco completo e poi assegnando a impianti
///
private bool RebalanceOrder()
{
// imposto variabili x calcoli...
bool answ = false;
bool directAssign = false;
int maxDepth = memLayer.ML.CRI("maxDepthRebalance");
OrderSetSim FullSet = new OrderSetSim();
OrderSetSim StartSet = new OrderSetSim();
OrderSetSim SetNe01 = new OrderSetSim();
OrderSetSim SetNe02 = new OrderSetSim();
OrderSetSim SetNe03 = new OrderSetSim();
// creo liste x i valori da processare...
Dictionary RawList = new Dictionary();
Dictionary OrderedList = new Dictionary();
// avvio cronometro
Log.Instance.Trace("Rebalance | S01");
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
// copio la tabella...
List listOrders = new List();
foreach (var item in TabOrders)
{
listOrders.Add(item);
}
foreach (var item in TabOrders)
{
RawList.Add(item.OrdID, item.EstProcTime);
}
int numOrdOrig = listOrders.Count;
Log.Instance.Trace($"Rebalance | S02 | listOrders.count: {numOrdOrig}");
// ordino la lista x processing successivo
OrderedList = RawList.OrderBy(x => x.Value).ToDictionary(t => t.Key, t => t.Value);
// inizio immaginando di usare TUTTI gli ordini
FullSet.OrderSet = OrderedList;
// calcolo i valori target iniziali
SetNe01.TargetValue = enable01 ? FullSet.ActualValue * Ratio01 : 0;
SetNe02.TargetValue = enable02 ? FullSet.ActualValue * Ratio02 : 0;
SetNe03.TargetValue = enable03 ? FullSet.ActualValue * Ratio03 : 0;
Log.Instance.Trace($"Rebalance | S03 | T01: {SetNe01.TargetValue} | T02: {SetNe02.TargetValue} | T03: {SetNe03.TargetValue}");
// salvo i set su cui lavorare, SE ho + ordini che macchine prendo i + lunghi x assegnaz. deterministica
int num2proc = numEnabled;
Log.Instance.Trace($"Rebalance | S04 | numEnabled: {numEnabled}");
if (OrderedList.Count > num2proc)
{
directAssign = true;
StartSet.OrderSet = OrderedList.OrderByDescending(x => x.Value).Take(num2proc).ToDictionary(t => t.Key, t => t.Value);
// tolgo ordini lunghi tra quelli da processare
foreach (var ordTaken in StartSet.OrderSet)
{
OrderedList.Remove(ordTaken.Key);
}
//OrderedList = OrderedList.OrderBy(x => x.Value).Take(OrderedList.Count - num2proc).ToDictionary(t => t.Key, t => t.Value);
// imposto nuovi target secondo sia abilitato
int idx = 0;
SetNe01.TargetValue -= enable01 ? StartSet.OrderSet.Skip(idx++).FirstOrDefault().Value : 0;
SetNe02.TargetValue -= enable02 ? StartSet.OrderSet.Skip(idx++).FirstOrDefault().Value : 0;
SetNe03.TargetValue -= enable03 ? StartSet.OrderSet.Skip(idx++).FirstOrDefault().Value : 0;
Log.Instance.Trace($"Rebalance | S05a | Target after direct assign | T01: {SetNe01.TargetValue} | T02: {SetNe02.TargetValue} | T03: {SetNe03.TargetValue}");
}
else
{
Log.Instance.Trace($"Rebalance | S05b | no direct assign | OrderedList.Count: {OrderedList.Count} | num2proc: {num2proc}");
}
// ciclo x riempire il + primo...SE manca ...
if (SetNe01.TargetValue > 0)
{
SetNe01.OrderSet = findLocalMin(OrderedList, SetNe01.TargetValue, maxDepth);
Log.Instance.Trace($"Rebalance | S06 | NE01 partial | SetNe01.ActualValue: {SetNe01.ActualValue}");
}
// calcolo il restante per differenza...
var ordRemain = OrderedList;
foreach (var item in SetNe01.OrderSet)
{
ordRemain.Remove(item.Key);
}
if (SetNe02.TargetValue > 0)
{
SetNe02.OrderSet = findLocalMin(ordRemain, SetNe02.TargetValue, maxDepth);
Log.Instance.Trace($"Rebalance | S07 | NE02 partial | SetNe02.ActualValue: {SetNe02.ActualValue}");
}
// l'ultimo è la differenza
if (SetNe03.TargetValue > 0)
{
SetNe03.OrderSet = ordRemain;
foreach (var item in SetNe02.OrderSet)
{
SetNe03.OrderSet.Remove(item.Key);
}
Log.Instance.Trace($"Rebalance | S08 | NE03 partial | SetNe03.ActualValue: {SetNe03.ActualValue}");
}
else
{
// riporto ai precedenti
if (enable02)
{
foreach (var item in ordRemain)
{
if (!SetNe02.OrderSet.ContainsKey(item.Key))
{
SetNe02.OrderSet.Add(item.Key, item.Value);
}
}
Log.Instance.Trace($"Rebalance | S09 | NE02 done | SetNe02.ActualValue: {SetNe02.ActualValue}");
}
else if (enable01)
{
foreach (var item in ordRemain)
{
if (!SetNe01.OrderSet.ContainsKey(item.Key))
{
SetNe01.OrderSet.Add(item.Key, item.Value);
}
}
Log.Instance.Trace($"Rebalance | S10 | NE01 done | SetNe01.ActualValue: {SetNe01.ActualValue}");
}
}
// se directAssign --> reinserisco i 3 ordini grandi
try
{
if (directAssign)
{
int idx = 0;
if (enable01)
{
var firstOrder01 = StartSet.OrderSet.Skip(idx++).FirstOrDefault();
SetNe01.OrderSet.Add(firstOrder01.Key, firstOrder01.Value);
Log.Instance.Trace($"Rebalance | S11 | NE01 done | SetNe01.ActualValue: {SetNe01.ActualValue} | SetNe01.OrderSet.Count: {SetNe01.OrderSet.Count}");
}
else
{
Log.Instance.Trace("enable01 == false");
}
if (enable02)
{
var firstOrder02 = StartSet.OrderSet.Skip(idx++).FirstOrDefault();
SetNe02.OrderSet.Add(firstOrder02.Key, firstOrder02.Value);
Log.Instance.Trace($"Rebalance | S12 | NE02 done | SetNe02.ActualValue: {SetNe02.ActualValue} | SetNe02.OrderSet.Count: {SetNe02.OrderSet.Count}");
}
else
{
Log.Instance.Trace("enable02 == false");
}
if (enable03)
{
var firstOrder03 = StartSet.OrderSet.Skip(idx++).FirstOrDefault();
SetNe03.OrderSet.Add(firstOrder03.Key, firstOrder03.Value);
Log.Instance.Trace($"Rebalance | S13 | NE03 done | SetNe03.ActualValue: {SetNe03.ActualValue} | SetNe03.OrderSet.Count: {SetNe03.OrderSet.Count}");
}
else
{
Log.Instance.Trace("enable03 == false");
}
}
}
catch (Exception exc)
{
Log.Instance.Error($"Exception durante rebalance 01:{Environment.NewLine}{exc}");
}
// 2024.09.20: controllo che il numero ordini torni o LO SEGNALO come errore...
int numAssigned = SetNe01.OrderSet.Count + SetNe02.OrderSet.Count + SetNe03.OrderSet.Count;
if (numAssigned != numOrdOrig)
{
divError.Visible = true;
Log.Instance.Error($"Error during rebalance | numOrdOrig: {numOrdOrig} | numAssigned: {numAssigned}");
lblError.Text = traduci("ERR_Rebalance01");
lblErrorDetail.Text = $"{traduci("ERR_Rebalance02")} | # Orig: {numOrdOrig} | # Assigned: {numAssigned}";
}
else
{
divError.Visible = false;
// check sul num di spostamenti1
int numMove = 0;
int numOk = 0;
Log.Instance.Trace("Rebalance | Starting final stage (DB modifications)");
try
{
// riorganizzo tabOrders...
foreach (var orderItem in TabOrders)
{
if (SetNe01.OrderSet.ContainsKey(orderItem.OrdID))
{
if (orderItem.BatchID != cmp_orderExtListNE01.BatchId)
{
DLMan.taOLT.updateBatch(orderItem.BatchID, orderItem.OrdID, cmp_orderExtListNE01.BatchId);
numMove++;
}
else
{
numOk++;
}
}
if (SetNe02.OrderSet.ContainsKey(orderItem.OrdID))
{
if (orderItem.BatchID != cmp_orderExtListNE02.BatchId)
{
DLMan.taOLT.updateBatch(orderItem.BatchID, orderItem.OrdID, cmp_orderExtListNE02.BatchId);
numMove++;
}
else
{
numOk++;
}
}
if (SetNe03.OrderSet.ContainsKey(orderItem.OrdID))
{
if (orderItem.BatchID != cmp_orderExtListNE03.BatchId)
{
DLMan.taOLT.updateBatch(orderItem.BatchID, orderItem.OrdID, cmp_orderExtListNE03.BatchId);
numMove++;
}
else
{
numOk++;
}
}
}
}
catch (Exception exc)
{
Log.Instance.Error($"Exception durante rebalance 02:{Environment.NewLine}{exc}");
}
answ = listOrders.Count > 0;
Log.Instance.Trace($"Final check | S14 | answ: {answ} | listOrders.Count: {listOrders.Count} | numMove: {numMove} | numOk: {numOk}");
// salvo tempo calcolo
stopWatch.Stop();
var elapsTime = stopWatch.Elapsed;
Log.Instance.Info($"Rebalance executed | R01: {Ratio01:P1}/{SetNe01.ActualValue / FullSet.ActualValue:P1} | R02: {Ratio02:P1}/{SetNe02.ActualValue / FullSet.ActualValue:P1} | R03: {Ratio03:P1}/{SetNe03.ActualValue / FullSet.ActualValue:P1} | maxDepth: {maxDepth} | elapsed ms: {elapsTime.TotalMilliseconds:N1}");
// resetto batch ordini...
ComLib.OrdersExtResetCache();
}
cmp_orderExtListNE01.doUpdate();
cmp_orderExtListNE02.doUpdate();
cmp_orderExtListNE03.doUpdate();
return answ;
}
///
/// Toggle generale pulsanti
///
///
private void toggleAll(bool enable)
{
// solo in caso di true...
if (enable)
{
enable01 = enable;
enable02 = enable;
enable03 = enable;
}
}
#endregion Private Methods
}
}