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 } }