Files
NKC/NKC_WF/WebUserControls/cmp_batchDetailSplit.ascx.cs
T
Samuele Locatelli aa122d625b - Update x primi test split 3 macchine
- log chiusura proc stima/nesting
2023-08-04 12:17:33 +02:00

599 lines
21 KiB
C#

using AppData;
using NKC_SDK;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace NKC_WF.WebUserControls
{
public partial class cmp_batchDetailSplit : BaseUserControl
{
#region Protected Properties
protected bool BatchIsAncestor
{
get
{
return ComLib.BType(BatchId) == BatchType.Ancestor;
}
}
/// <summary>
/// Status corrente del batch
/// </summary>
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 lastRatio01
{
get
{
int answ = 50;
if (!string.IsNullOrEmpty(hfLastRatio01.Value))
{
int.TryParse(hfLastRatio01.Value, out answ);
}
return answ;
}
set
{
hfLastRatio01.Value = $"{value}";
}
}
protected int lastRatio02
{
get
{
int answ = 50;
if (!string.IsNullOrEmpty(hfLastRatio02.Value))
{
int.TryParse(hfLastRatio02.Value, out answ);
}
return answ;
}
set
{
hfLastRatio02.Value = $"{value}";
}
}
protected int lastRatio03
{
get
{
int answ = 50;
if (!string.IsNullOrEmpty(hfLastRatio03.Value))
{
int.TryParse(hfLastRatio03.Value, out answ);
}
return answ;
}
set
{
hfLastRatio03.Value = $"{value}";
}
}
protected bool needSave
{
get
{
bool answ = true;
bool.TryParse(hfNeedSave.Value, out answ);
return answ;
}
set
{
hfNeedSave.Value = $"{value}";
}
}
/// <summary>
/// Tabella dei batch Descendant di quello corrente
/// </summary>
protected DS_App.BatchListDataTable TabBatchDesc
{
get
{
return ComLib.BatchDescendant(BatchId);
}
}
protected DS_App.OrderListTreeDataTable TabOrders
{
get
{
// cerco in redis
return ComLib.OrdersExtByBatch(BatchId);
}
}
protected double totTime01
{
get
{
double answ = 0;
DS_App.OrderListTreeDataTable tabNe01 = DLMan.taOLT.getByBatch(cmp_orderExtListNE01.BatchId);
answ = tabNe01.Sum(x => x.EstProcTime);
return answ;
}
}
protected double totTime02
{
get
{
double answ = 0;
DS_App.OrderListTreeDataTable tabNe02 = DLMan.taOLT.getByBatch(cmp_orderExtListNE02.BatchId);
answ = tabNe02.Sum(x => x.EstProcTime);
return answ;
}
}
protected double totTime03
{
get
{
double answ = 0;
DS_App.OrderListTreeDataTable tabNe03 = DLMan.taOLT.getByBatch(cmp_orderExtListNE03.BatchId);
answ = tabNe03.Sum(x => x.EstProcTime);
return answ;
}
}
#if false
protected int valRatio
{
get
{
int answ = 50;
if (!string.IsNullOrEmpty(txtRatio.Text))
{
int.TryParse(txtRatio.Text, out answ);
}
return answ;
}
set
{
txtRatio.Text = $"{value}";
// scrivo ANCHE i valori assoluti
lblRatio01.Text = $"{100 - valRatio} %";
lblRatio02.Text = $"{valRatio} %";
lblTime01.Text = $"{fullTime * (100 - value) / (100 * 60):N2} h";
lblTime02.Text = $"{fullTime * value / (100 * 60):N2} h";
}
}
#endif
#endregion Protected Properties
#region Public Properties
public int BatchId
{
set
{
hfBatchId.Value = value.ToString();
if (BatchId > 0)
{
checkCreateDescendant();
doUpdate();
}
fixRatio();
}
get
{
int answ = 0;
int.TryParse(hfBatchId.Value, out answ);
return answ;
}
}
public bool isSplitted
{
get
{
bool answ = false;
bool.TryParse(hfIsSplit.Value, out answ);
return answ;
}
set
{
hfIsSplit.Value = $"{value}";
}
}
#endregion Public Properties
protected int Ratio01 = 0;
protected int Ratio02 = 0;
protected int Ratio03 = 0;
#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);
}
}
}
/// <summary>
/// verifico modalità display (editing solo se PRIMA di lanciare nesting...)
/// </summary>
private void checkDisplayMode()
{
#if false
txtRatio.Visible = (BatchIsAncestor && CurrBatchStatus <= BatchStatus.EstimationDone);
#endif
var splitEnab = (BatchIsAncestor && CurrBatchStatus <= BatchStatus.EstimationDone);
// 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;
}
private void Cmp_orderExtListNE01_eh_doRefresh(object sender, EventArgs e)
{
// sposto ordine in altro set
DLMan.taOLT.updateBatch(cmp_orderExtListNE01.BatchId, cmp_orderExtListNE01.SelOrderId, cmp_orderExtListNE02.BatchId);
fixChildBatch();
fixRatio();
}
private void Cmp_orderExtListNE02_eh_doRefresh(object sender, EventArgs e)
{
// sposto ordine in altro set
DLMan.taOLT.updateBatch(cmp_orderExtListNE02.BatchId, cmp_orderExtListNE02.SelOrderId, cmp_orderExtListNE01.BatchId);
fixChildBatch();
fixRatio();
}
private void Cmp_orderExtListNE03_eh_doRefresh(object sender, EventArgs e)
{
// sposto ordine in altro set
DLMan.taOLT.updateBatch(cmp_orderExtListNE03.BatchId, cmp_orderExtListNE03.SelOrderId, cmp_orderExtListNE01.BatchId);
fixChildBatch();
fixRatio();
}
private void fixChildBatch()
{
// sistemo dati ordini
DS_App.BatchListDataTable TabBatch = TabBatchDesc;
cmp_orderExtListNE01.BatchId = TabBatch.Rows.Count > 0 ? TabBatchDesc[0].BatchID : 0;
cmp_orderExtListNE02.BatchId = TabBatch.Rows.Count > 1 ? TabBatchDesc[1].BatchID : 0;
cmp_orderExtListNE03.BatchId = TabBatch.Rows.Count > 2 ? TabBatchDesc[2].BatchID : 0;
cmp_orderExtListNE01.doUpdate();
cmp_orderExtListNE02.doUpdate();
cmp_orderExtListNE03.doUpdate();
cmp_batchDetailSplitInfoNE01.BatchId = cmp_orderExtListNE01.BatchId;
cmp_batchDetailSplitInfoNE02.BatchId = cmp_orderExtListNE02.BatchId;
cmp_batchDetailSplitInfoNE03.BatchId = cmp_orderExtListNE03.BatchId;
}
private void fixRatio()
{
// calcolo tempi....
double tmpTime = totTime01 + totTime02 + totTime03;
fullTime = tmpTime > 0 ? tmpTime : 1;
// sistemazione ratio calcolate...
Ratio01 = (int)(totTime01 * 100 / fullTime);
Ratio02 = (int)(totTime02 * 100 / fullTime);
Ratio03 = (int)(totTime03 * 100 / fullTime);
lastRatio01 = Ratio01;
lastRatio02 = Ratio02;
lastRatio03 = Ratio03;
#if false
double newRatio = (totTime02 * 100 / fullTime);
valRatio = (int)newRatio;
lastValRatio = valRatio;
#endif
}
/// <summary>
/// effettua ribilanciamento ordini partendo da elenco completo e poi assegnando a impianti
/// </summary>
private void rebalanceOrder()
{
// solo se variato il ratio...
if (Ratio01 != lastRatio01 || Ratio02 != lastRatio02 || Ratio03 != lastRatio03)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
// costruisco vettore durata ordini
OrderSetSim FullSet = new OrderSetSim();
OrderSetSim SetNe01 = new OrderSetSim();
OrderSetSim SetNe02 = new OrderSetSim();
OrderSetSim SetNe03 = new OrderSetSim();
// creo liste x i valori da processare...
Dictionary<int, double> RawList = new Dictionary<int, double>();
Dictionary<int, double> OrderedList = new Dictionary<int, double>();
foreach (var item in TabOrders)
{
RawList.Add(item.OrdID, item.EstProcTime);
}
// ordino la lista x processing successivo
OrderedList = RawList.OrderBy(x => x.Value).ToDictionary(t => t.Key, t => t.Value);
// imposto maxDepth ...
int maxDepth = 8;
// salvo i set
FullSet.OrderSet = OrderedList;
// FIXME TODO !!! valutare se partire dal +m piccolo al + grande...
// ciclo x riempire il + primo...
SetNe01.TargetValue = FullSet.ActualValue * (double)Ratio01/100;
SetNe02.TargetValue = FullSet.ActualValue * (double)Ratio02 / 100;
SetNe03.TargetValue = FullSet.ActualValue * (double)Ratio03 / 100;
SetNe01.OrderSet = findLocalMin(OrderedList, SetNe01.TargetValue, maxDepth);
// calcolo il restante per differenza...
var ordRemain = OrderedList;
foreach (var item in SetNe01.OrderSet)
{
ordRemain.Remove(item.Key);
}
SetNe02.OrderSet = findLocalMin(ordRemain, SetNe02.TargetValue, maxDepth);
// l'ultimo è la differenza
SetNe03.OrderSet = ordRemain;
foreach (var item in SetNe02.OrderSet)
{
SetNe03.OrderSet.Remove(item.Key);
}
// 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);
}
}
else if (SetNe02.OrderSet.ContainsKey(orderItem.OrdID))
{
if (orderItem.BatchID != cmp_orderExtListNE02.BatchId)
{
DLMan.taOLT.updateBatch(orderItem.BatchID, orderItem.OrdID, cmp_orderExtListNE02.BatchId);
}
}
else
{
if (orderItem.BatchID != cmp_orderExtListNE03.BatchId)
{
DLMan.taOLT.updateBatch(orderItem.BatchID, orderItem.OrdID, cmp_orderExtListNE03.BatchId);
}
}
}
// --> richiede salvataggio
needSave = true;
// salvo tempo calcolo
stopWatch.Stop();
Log.Instance.Info($"Rebalance executed | R01: {Ratio01} | R02: {Ratio02} | R03: {Ratio03} | maxDepth: {maxDepth} | elapsed ms: {stopWatch.ElapsedMilliseconds}");
}
fixRatio();
}
#endregion Private Methods
#region Protected Methods
/// <summary>
/// Cerca il set con lo score migliore calcolando x subset della lista ordinata
/// </summary>
/// <param name="OrderedList">Lista ordinata oggetti (INT) + valore</param>
/// <param name="TargetVal">Valore desiderato (come SOMMA)</param>
/// <param name="maxDepth">Massima profondità ricorsione accettata (x evitare loop infinito)</param>
/// <returns></returns>
protected Dictionary<int, double> findLocalMin(Dictionary<int, double> OrderedList, double TargetVal, int maxDepth)
{
Dictionary<int, double> answ = new Dictionary<int, double>();
List<OrderSetSim> Candidates = new List<OrderSetSim>();
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<int, double> 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<int, double> 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<int, double> 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<int, double> 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;
}
/// <summary>
/// Cerca il set della lista ordinata <= target val
/// </summary>
/// <param name="OrderedList">Lista ordinata oggetti (INT) + valore</param>
/// <param name="TargetVal">Valore desiderato (come SOMMA)</param>
/// <returns></returns>
protected Dictionary<int, double> findStepMin(Dictionary<int, double> OrderedList, double TargetVal)
{
double CurrVal = 0;
Dictionary<int, double> answ = new Dictionary<int, double>();
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)
{
//valRatio = 51;
//lastValRatio = 0;
Ratio01 = 33;
Ratio02 = 33;
Ratio03 = 34;
lastRatio01 = 0;
lastRatio02 = 0;
lastRatio03 = 0;
doUpdate();
}
private int numMach = 3;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// verifica visualizzazione
fixChildBatch();
fixRatio();
checkDisplayMode();
}
cmp_orderExtListNE01.eh_doRefresh += Cmp_orderExtListNE01_eh_doRefresh;
cmp_orderExtListNE02.eh_doRefresh += Cmp_orderExtListNE02_eh_doRefresh;
cmp_orderExtListNE03.eh_doRefresh += Cmp_orderExtListNE03_eh_doRefresh;
}
#if false
protected void txtRatio_TextChanged(object sender, EventArgs e)
{
doUpdate();
}
#endif
#endregion Protected Methods
#region Public Methods
public void doUpdate()
{
rebalanceOrder();
fixChildBatch();
checkDisplayMode();
raiseReset();
}
#endregion Public Methods
}
}