Files
NKC/NKC_WF/WebUserControls/cmp_batchDetail.ascx.cs
T
2021-06-11 18:22:44 +02:00

654 lines
25 KiB
C#

using AppData;
using NKC_SDK;
using SteamWare;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NKC_WF.WebUserControls
{
public partial class cmp_batchDetail : BaseUserControl
{
#region Protected Fields
// place master hard-coded
protected string PlaceCod = "VIRTNE";
#endregion Protected Fields
#region Protected Properties
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 lastValRatio
{
get
{
int answ = 50;
if (!string.IsNullOrEmpty(hfLastRatio.Value))
{
int.TryParse(hfLastRatio.Value, out answ);
}
return answ;
}
set
{
hfLastRatio.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 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 = $"{valRatio} %";
lblRatio02.Text = $"{100 - valRatio} %";
lblTime01.Text = $"{fullTime * value / (100 * 60):N2} h";
lblTime02.Text = $"{fullTime * (100 - value) / (100 * 60):N2} h";
}
}
#endregion Protected Properties
#region Public Properties
public int BatchId
{
set
{
hfBatchId.Value = value.ToString();
frmView.DataBind();
lblMatDet.Text = "";
lblProdDet.Text = "";
if (memLayer.ML.CRB("enableMongo"))
{
// cerco da lista salvataggi Estim/Nest...
var estimAnsw = ComLib.man.getEstAnsw(value);
var nestAnsw = ComLib.man.getNestAnsw(value);
StringBuilder sbDebug = new StringBuilder();
sbDebug.AppendLine("Debug Info:");
// elenchi x ricerca duplicati
List<int> partListEstim = new List<int>();
List<int> partListEstimDupl = new List<int>();
List<int> partListNest = new List<int>();
List<int> partListNestDupl = new List<int>();
if (estimAnsw != null)
{
try
{
foreach (var part in estimAnsw.PartList)
{
if (partListEstim.Contains(part.PartId))
{
partListEstimDupl.Add(part.PartId);
}
else
{
partListEstim.Add(part.PartId);
}
}
}
catch
{ }
try
{
sbDebug.AppendLine($"ESTIM: EnvNum: {estimAnsw.EnvNum} | Worktime: {estimAnsw.EstimatedWorktime / 60:N2} min | Processing Runtime {estimAnsw.ProcessingRuntime / 60:N2} min | Parts #: {estimAnsw.PartList.Count} | Distinct Part # {partListEstim.Count}");
// se ho duplicati indico:
if (partListEstimDupl.Count > 0)
{
sbDebug.AppendLine("---------------------");
sbDebug.AppendLine($"ESTIM: FOUND {partListEstimDupl.Count} duplicate:");
foreach (var partId in partListEstimDupl)
{
sbDebug.AppendLine($"{partId}");
}
sbDebug.AppendLine("---------------------");
}
}
catch
{ }
}
if (nestAnsw != null)
{
try
{
if (nestAnsw.BunkList != null)
{
foreach (var bunk in nestAnsw.BunkList)
{
foreach (var sheet in bunk.SheetList)
{
foreach (var part in sheet.PartList)
{
if (partListNest.Contains(part.PartId))
{
partListNestDupl.Add(part.PartId);
}
else
{
partListNest.Add(part.PartId);
}
}
}
}
}
}
catch
{ }
int totKit = 0;
try
{
if (nestAnsw.CartList != null)
{
foreach (var cart in nestAnsw.CartList)
{
totKit += cart.KitList.Count;
}
}
}
catch
{ }
//il tot delle part è in bunk > Sheet > part
int totPartNum = 0;
int totSheet = 0;
List<int> materialsList = new List<int>();
double num = 0;
double den = 1;
double currRatio = 0;
List<double> workRatio = new List<double>();
try
{
if (nestAnsw.BunkList != null)
{
foreach (var bunk in nestAnsw.BunkList)
{
totSheet += bunk.SheetList.Count;
foreach (var sheet in bunk.SheetList)
{
totPartNum += sheet.PartList.Count;
num = sheet.SurfaceWork > 0 ? sheet.SurfaceWork : 0;
den = sheet.SurfaceTotal > 0 ? sheet.SurfaceTotal : 1;
currRatio = ratioProt(num, den);
workRatio.Add(currRatio);
if (!materialsList.Contains(sheet.MatId))
{
materialsList.Add(sheet.MatId);
}
}
}
}
}
catch
{ }
try
{
// ordino le medie
workRatio.Sort();
// elimino le + basse quanti materiali ci sono...
workRatio.RemoveRange(0, materialsList.Count);
double avgRatio = workRatio.Average();
double minRatio = workRatio.Min();
double maxRatio = workRatio.Max();
sbDebug.AppendLine($"NEST: EnvNum: {nestAnsw.EnvNum} | Worktime: {nestAnsw.EstimatedWorktime / 60:N2} min | Processing Runtime {nestAnsw.ProcessingRuntime / 60:N2} min");
lblMatDet.Text = $"avg: <b>{avgRatio:P1}</b> (<b>{minRatio:P1}</b> &rarr; <b>{maxRatio:P1}</b>) | {materialsList.Count} materials";
lblProdDet.Text = $"Bunks: <b>{nestAnsw.BunkList.Count}</b> | Sheets: <b>{totSheet}</b> | Carts: <b>{nestAnsw.CartList.Count}</b> | Bins: <b>{nestAnsw.BinList.Count}</b>";
// se ho duplicati indico:
if (partListNestDupl.Count > 0)
{
sbDebug.AppendLine("---------------------");
sbDebug.AppendLine($"NEST: FOUND {partListNestDupl.Count} duplicate:");
foreach (var partId in partListNestDupl)
{
sbDebug.AppendLine($"{partId}");
}
sbDebug.AppendLine("---------------------");
}
// s enon corrispondono
if (partListEstim.Count != partListNest.Count)
{
sbDebug.AppendLine("---------------------");
if (partListEstim.Count > partListNest.Count)
{
sbDebug.AppendLine($"EST OK | NEST missing:");
foreach (var partId in partListEstim)
{
if (!partListNest.Contains(partId))
{
sbDebug.AppendLine($"{partId}");
}
}
}
else
{
sbDebug.AppendLine($"EST missing | NEST OK:");
foreach (var partId in partListNest)
{
if (!partListEstim.Contains(partId))
{
sbDebug.AppendLine($"{partId}");
}
}
}
sbDebug.AppendLine("---------------------");
}
}
catch
{ }
}
if (memLayer.ML.CRS("environment") == "DEV")
{
lblTestJson.Text = "<hr/>" + sbDebug.Replace("\r\n", "<br/>").ToString();
}
}
if (BatchId > 0)
{
checkCreateDescendant();
showBatchDescendant();
fixChildBatch();
}
}
get
{
int answ = 0;
int.TryParse(hfBatchId.Value, out answ);
return answ;
}
}
/// <summary>
/// verifica possibilità avvio TASK x presenza task NON chiusi
/// </summary>
/// <returns></returns>
public bool canStartNew
{
get
{
return ComLib.canStartNew;
}
}
#endregion Public 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);
}
}
}
private void fixChildBatch()
{
DS_App.BatchListDataTable TabBatch = TabBatchDesc;
cmp_orderExtListNE01.BatchId = TabBatch.Rows.Count > 0 ? TabBatchDesc[0].BatchID : 0;
cmp_orderExtListNE02.BatchId = TabBatch.Rows.Count > 0 ? TabBatchDesc[1].BatchID : 0;
cmp_orderExtListNE01.doUpdate();
cmp_orderExtListNE02.doUpdate();
}
private void fixRatio()
{
// sistemazione ratio calcolata...
DS_App.OrderListTreeDataTable tabNe01 = DLMan.taOLT.getByBatch(cmp_orderExtListNE01.BatchId);
DS_App.OrderListTreeDataTable tabNe02 = DLMan.taOLT.getByBatch(cmp_orderExtListNE02.BatchId);
double totTime01 = tabNe01.Sum(x => x.EstProcTime);
double totTime02 = tabNe02.Sum(x => x.EstProcTime);
// aggiorno valore ratio e ratio last...
fullTime = totTime01 + totTime02;
fullTime = fullTime > 0 ? fullTime : 1;
double newRatio = (totTime01 * 100 / fullTime);
valRatio = (int)newRatio;
lastValRatio = valRatio;
}
/// <summary>
/// effettua ribilanciamento ordini partendo da elenco completo e poi assegnando a impianti
/// </summary>
private void rebalanceOrder()
{
// solo se variato il ratio...
if (valRatio != lastValRatio)
{
// costruisco vettore durata ordini
OrderSetSim FullSet = new OrderSetSim();
OrderSetSim SetNe01 = new OrderSetSim();
OrderSetSim SetNe02 = 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);
// salvo i set
FullSet.OrderSet = OrderedList;
// lavoro sull'ottimizzare il MINORE
double ValRatio = (double)valRatio / 100;
if (ValRatio <= 0.5)
{
SetNe01.TargetValue = FullSet.ActualValue * ValRatio;
SetNe01.OrderSet = findLocalMin(OrderedList, SetNe01.TargetValue);
// l'altro è la differenza
SetNe02.OrderSet = OrderedList;
foreach (var item in SetNe01.OrderSet)
{
SetNe02.OrderSet.Remove(item.Key);
}
}
else
{
SetNe02.TargetValue = FullSet.ActualValue * (1 - ValRatio);
SetNe02.OrderSet = findLocalMin(OrderedList, SetNe02.TargetValue);
// l'altro è la differenza
SetNe01.OrderSet = OrderedList;
foreach (var item in SetNe02.OrderSet)
{
SetNe01.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 (orderItem.BatchID != cmp_orderExtListNE02.BatchId)
{
DLMan.taOLT.updateBatch(orderItem.BatchID, orderItem.OrdID, cmp_orderExtListNE02.BatchId);
}
}
}
// --> richiede salvataggio
needSave = true;
}
fixRatio();
}
/// <summary>
/// Mostro dati dei Batch descendant
/// </summary>
private void showBatchDescendant()
{
// suddivido
rebalanceOrder();
}
#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 (comeSOMMA)</param>
/// <returns></returns>
protected Dictionary<int, double> findLocalMin(Dictionary<int, double> OrderedList, double TargetVal)
{
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);
// se rimane qualcosa...
if (OrdInf != null && OrdInf.Any())
{
// calcolo il minimo locale nei 2 casi, da soli
Dictionary<int, double> TestOrderSet01 = findLocalMin(OrdInf, TargetVal);
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);
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;
}
protected void lbtAccept_Click(object sender, EventArgs e)
{
// registro accettazione Nesting
DLMan.taBL.acceptBatch(BatchId, DLMan.CodSoggCurrUser);
raiseEvent();
}
protected void lbtSendEstim_Click(object sender, EventArgs e)
{
// invia a redis una richiesta...
ComLib.sendMaterials();
ComLib.sendBatchReq(BatchId, "Estimation", 3, false);
// registro su DB nesting iniziato...
DLMan.taBL.updateStatus(BatchId, (int)BatchStatus.EstimationRequested, "", 0);
raiseEvent();
}
protected void lbtSendNesting_Click(object sender, EventArgs e)
{
// invia a redis a a richiesta...
ComLib.sendMaterials();
ComLib.sendBatchReq(BatchId, "Nesting", 2, false);
// registro su DB nesting iniziato...
DLMan.taBL.updateStatus(BatchId, (int)BatchStatus.NestRequested, "", -1);
raiseEvent();
}
protected void lbtStopEstim_Click(object sender, EventArgs e)
{
// resetto richiesta
ComLib.resetBatchReq();
// registro su DB nesting iniziato...
DLMan.taBL.updateStatus(BatchId, (int)BatchStatus.Imported, "", -1);
raiseEvent();
}
protected void lbtStopNesting_Click(object sender, EventArgs e)
{
// resetto richiesta
ComLib.resetBatchReq();
// registro su DB nesting iniziato...
DLMan.taBL.updateStatus(BatchId, (int)BatchStatus.EstimationDone, "", -1);
raiseEvent();
}
/// <summary>
/// Init di base
/// </summary>
/// <param name="e"></param>
protected override void OnInit(EventArgs e)
{
checkCreateDescendant();
}
protected void Page_Load(object sender, EventArgs e)
{
}
/// <summary>
/// Effettua divisione evitando zeri a den...
/// </summary>
/// <param name="num"></param>
/// <param name="den"></param>
/// <returns></returns>
protected double ratioProt(double num, double den)
{
den = den == 0 ? 1 : den;
return num / den;
}
protected void txtRatio_TextChanged(object sender, EventArgs e)
{
rebalanceOrder();
fixChildBatch();
}
#endregion Protected Methods
#region Internal Methods
internal void doUpdate()
{
frmView.DataBind();
}
#endregion Internal Methods
#region Public Methods
/// <summary>
/// Converte il codice stato in effettivo campo
/// </summary>
/// <param name="_status"></param>
/// <returns></returns>
public string BStatus(object _status)
{
string answ = ComLib.BatchStatusDescr(_status);
return answ;
}
/// <summary>
/// Controlla se lo stato sia uguale a quello richiesto
/// </summary>
/// <param name="_status"></param>
/// <param name="statusReq"></param>
/// <returns></returns>
public bool checkStatus(object _status, BatchStatus statusReq)
{
bool answ = false;
int status = -1;
int.TryParse(_status.ToString(), out status);
answ = (status == (int)statusReq);
return answ;
}
#endregion Public Methods
}
}