using EgwCoreLib.Lux.Core.Generic; using EgwCoreLib.Razor; using static EgwCoreLib.Lux.Core.Enums; namespace Lux.UI.Components.Pages { public partial class Orders { #region Protected Enums /// /// Stato Ordine /// protected enum CompileStep { Draft = 0, Header = 1, General, Rows, Delivery, FinalCheck } #endregion Protected Enums #region Protected Methods protected override void OnParametersSet() { // preparo sel periodo custom (traduzioni)... CustomSelDict = Enum.GetValues(typeof(DtUtils.PeriodSet)) .Cast() .ToDictionary(e => e, e => Traduci("periodo_" + e.ToString())); } #endregion Protected Methods #region Private Fields private string apiUrl = ""; private static Logger Log = LogManager.GetCurrentClassLogger(); private List AllConfEnvir = new(); private List AllRecords = new List(); /// /// Base path x network share files /// private string basePath = "unsafe_uploads"; private int currPage = 1; private CompileStep currStep = CompileStep.Draft; private OrderModel? EditRecord = null; private OrderModel? EditStateRec = null; private bool isLoading = false; private List JobQueueDone = new List(); private List JobQueueRun = new List(); private List JobQueueWait = new List(); private List ListFilt = new List(); private List ListRecords = new List(); private int numRecord = 10; private List OrderHist = new List(); /// /// Periodo selezionato attuale /// private EgwCoreLib.Utils.DtUtils.Periodo PeriodoSel = new EgwCoreLib.Utils.DtUtils.Periodo(EgwCoreLib.Utils.DtUtils.PeriodSet.ThisYear); private string searchVal = ""; private OrderModel? SelRecord = null; private int totalCount = 0; private BootstrapModal Modal = new(); private string mTitle = ""; private string mMessage = ""; private BootstrapModal.ModalMode mMode = BootstrapModal.ModalMode.ND; private Dictionary modalOpt = new Dictionary(); /// /// Periodo custom selezione valori /// private Dictionary? CustomSelDict = new(); #endregion Private Fields #region Private Properties private Enums.OrderStates? filtState { get; set; } = null; private List listBord01 { get; set; } = new(); [Inject] private IConfiguration Config { get; set; } = null!; [Inject] private ICalcRuidService CRService { get; set; } = null!; private string DivMainCss { get => SelRecord != null ? "col-6" : "col-12"; } [Inject] private IDataLayerServices DLService { get; set; } = null!; [Inject] private IProductionItemService PIService { get; set; } = default!; [Inject] private IOrderService OrdService { get; set; } = null!; [Inject] private IEnvirParamService EPService { get; set; } = null!; /// /// Filtro stato ordini /// protected Enums.OrderStates? FiltState { get => filtState; set { if (filtState != value) { filtState = value; DoFilter(); UpdateTable(); } } } private EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS filtEnv { get; set; } = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.BEAM; private EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS FiltEnv { get => filtEnv; set { if (filtEnv != value) { filtEnv = value; DoFilter(); UpdateTable(); } } } [Inject] private IJSRuntime JSRuntime { get; set; } = null!; [Inject] private IProdService PService { get; set; } = null!; #endregion Private Properties #region Private Methods private string CheckSelect(OrderModel curRec) { string answ = ""; if (SelRecord != null) { answ = curRec.OfferID == SelRecord.OfferID ? "table-info" : ""; } return answ; } private void DoAdd() { EditRecord = new OrderModel() { RefYear = DateTime.Today.Year, Description = $"Nuova Offerta {DateTime.Today:ddd yyyy.MM.dd}", ValidUntil = DateTime.Today.AddMonths(1) }; } private void DoEdit(OrderModel curRec) { currStep = CompileStep.Header; EditRecord = curRec; } private async Task DoGenFabbisogni(OrderModel curRec) { mTitle = "Attenzione"; mMessage = "Confermi di voler generare i fabbisogni per tutte le righe mancanti?"; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; isLoading = true; await InvokeAsync(StateHasChanged); // chiamo procedura creazione fabbisogni... List listReq = curRec.OrderRowNav.ToList(); await MRService.ReconcileOrderRowsAsync(listReq); await ReloadDataAsync(); UpdateTable(); isLoading = false; } [Inject] private IMatReqService MRService { get; set; } = null!; private void DoReset() { EditRecord = null; SelRecord = null; } private void DoSelect(OrderModel curRec) { SelRecord = curRec; } protected override async Task OnInitializedAsync() { // prendo il trim corrente + anno precedente... PeriodoSel = new EgwCoreLib.Utils.DtUtils.Periodo(EgwCoreLib.Utils.DtUtils.PeriodSet.ThisTrim); PeriodoSel.Inizio = PeriodoSel.Inizio.AddYears(-1); SetupArrows(); ConfInit(); await ReloadBaseData(); await ReloadDataAsync(); UpdateTable(); } /// /// Rimette un Job da coda running in waiting /// /// private async Task ReRunJob(string? JobCode) { if (!string.IsNullOrEmpty(JobCode)) { mTitle = "Attenzione"; mMessage = "Sicuro di voler rimettere in coda il calcolo?"; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; if (EditStateRec != null) { await PService.ReRunJobAsync(EditStateRec.Envir, JobCode); await UpdateJobQueue(EditStateRec.Envir); } } } /// /// Reseet History dell'ordine /// /// /// private async Task ResetHistory(OrderModel currRec) { mTitle = "Attenzione"; mMessage = "Sicuro di voler resettare l'history dell'ordine corrente? L'operazione non è revertibile."; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; currRec.LogHistory = new List(); OrderHist = currRec.LogHistory; await OrdService.UpsertAsync(currRec); } /// /// Resetta coda running riportandoli in waiting /// /// private async Task ResetRunQueue() { mTitle = "Attenzione"; mMessage = "Sicuro di voler resettare la coda di run calcolo? Le richieste verranno riaccodate in waiting."; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; if (EditStateRec != null) { await PService.ResetRunningAsync(EditStateRec.Envir); await UpdateJobQueue(EditStateRec.Envir); } } /// /// Resetta coda waiting eliminando task /// /// private async Task ResetWaitQueue() { mTitle = "Attenzione"; mMessage = "Sicuro di voler resettarela coda di attesa calcolo eliminando le richieste in attesa? L'operazione non è revertibile."; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; if (EditStateRec != null) { await PService.QueueResetAsync(EditStateRec.Envir, ProdQueueType.waiting); await UpdateJobQueue(EditStateRec.Envir); } } /// /// Manda l'ordine in fase di estimation /// /// private async Task SendEstim(OrderModel currRec) { /* --------------------------------- * Manda in stima l'ordine: * - genera Json richiesta * - salva in cache REDIS + invia richiesta via channel Redis * - prepara x visualizzazione l'history * - registra l'history serializzata sul record.. * --------------------------------- */ mTitle = "Attenzione"; mMessage = "Confermi di voler inviare una richiesta di stima tempi per l'ordine in oggetto? L'esecuzione non avverà in realtime e sarà accodata per l'esecuzione."; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; // processo riga ordine x riga ordine creando per ogni riga una richiesta... if (currRec.OrderRowNav != null && currRec.OrderRowNav.Count > 0) { // verifico parametri da conf envir... var envRec = AllConfEnvir.FirstOrDefault(x => x.EnvirID == currRec.Envir); Egw.Window.Data.Enums.QuestionModes cMode = Egw.Window.Data.Enums.QuestionModes.ORDER; Egw.Window.Data.Enums.QuestionOrderSubModes cSubMode = Egw.Window.Data.Enums.QuestionOrderSubModes.ESTIMATE; string reqKey = ""; string ordUid = currRec.OrderCode; foreach (var rigaOrd in currRec.OrderRowNav) { // preparo le 2 richieste (creazione, stima) CalcRequestDTO calcReq = new CalcRequestDTO(); bool needCalc = false; // recupero elenco items collegati alla riga d'ordine List TagsList = new(); var ProdList = await PIService.GetByOrderRowAsync(rigaOrd.OrderRowID); if (ProdList != null && ProdList.Count > 0) { TagsList = ProdList.Select(x => x.ProdItemTag ?? "").ToList(); } //string serTagList = JsonConvert.SerializeObject(TagList); string serTagList = string.Join(",", TagsList); // preparo richiesta serializzata e la accodo (viene inviata richiesta calcolo) Dictionary dictArgs = new Dictionary(); dictArgs.Add("UID", rigaOrd.OrderRowUID); // creo registrazione richiesta... var ruid = await CRService.AddRequestAsync($"{currRec.Envir}", $"{(int)cMode}-{(int)cSubMode}", rigaOrd.OrderRowUID); // aggiungo RUID effettivo dictArgs.Add("RUID", ruid); //string ordUid = rigaOrd.OrderNav.OrderCode; dictArgs.Add("OrderUID", ordUid); dictArgs.Add("Mode", $"{(int)cMode}"); dictArgs.Add("TagList", serTagList); // aggiungo file secondo ambiente... string serKey = envRec != null ? envRec.SerStrucKey : "SerializedData"; switch (currRec.Envir) { case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW: dictArgs.Add(serKey, rigaOrd.SerStruct); needCalc = rigaOrd.SerStruct.Length > 2; break; case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.BEAM: case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WALL: case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.CABINET: // rileggo da file... 2check, spostare?!? string folderPath = FolderPath(currRec.OfferID); string rawData = FileUtils.LoadFileContent(Path.Combine(basePath, folderPath), rigaOrd.FileResource); dictArgs.Add(serKey, rawData); dictArgs.Add("FileName", rigaOrd.FileName); needCalc = rawData.Length > 2; break; case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.NULL: default: break; } // solo SE va calcolato... if (needCalc) { // ora richiedo la stima, rimuovendo serializzato (serKey), fileName e tagList... dictArgs.Remove(serKey); dictArgs.Remove("FileName"); dictArgs.Remove("TagList"); //... e infine cambio il submode... dictArgs.Remove("SubMode"); cSubMode = Egw.Window.Data.Enums.QuestionOrderSubModes.ESTIMATE; dictArgs.Add("SubMode", $"{(int)cSubMode}"); calcReq = new CalcRequestDTO() { DictExec = dictArgs, EnvType = currRec.Envir }; // chiave: composta da cMode, submode, UID riga... reqKey = $"{cMode}:{cSubMode}:{rigaOrd.OrderRowUID}"; await PService.EnqueueRequestAsync("Estimation", reqKey, calcReq); // parto dalla history attuale var currHist = currRec.LogHistory; // aggiungo evento... currHist.Add(new TaskHistDTO() { DtEvent = DateTime.Now, UserName = "Default User", Message = $"{reqKey}", IconCss = "fa-solid fa-hourglass-start" }); currRec.LogHistory = currHist; OrderHist = currRec.LogHistory; await OrdService.UpsertAsync(currRec); } } } await UpdateJobQueue(currRec.Envir); } private void AdvStep(CompileStep newStep) { currStep = newStep; } private string ArrowBackCol(CompileStep arrowStep) { string answ = $"fill: #000000;"; if (arrowStep == currStep) { answ = $"fill: #123456;"; } else if (arrowStep < currStep) { answ = $"fill: #456789;"; } else { answ = $"fill: #89ABCD;"; } return answ; } private void ConfInit() { basePath = Config.GetValue("ServerConf:FileSharePath") ?? "unsafe_uploads"; apiUrl = Config.GetValue("ServerConf:ReportUrl") ?? ""; } private void DoClose() { EditRecord = null; } private void DoFilter() { // verifico eventuali filtri ListFilt = AllRecords .Where(x => (filtState == null || x.OrderState == filtState) && (filtEnv == EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.NULL || x.Envir == FiltEnv) ) .ToList(); if (!string.IsNullOrEmpty(searchVal)) { ListFilt = ListFilt .Where(x => x.Description.Contains(searchVal, StringComparison.InvariantCultureIgnoreCase) || x.OrderCode.Contains(searchVal, StringComparison.InvariantCultureIgnoreCase)) .ToList(); } totalCount = ListFilt.Count(); currPage = 1; SelRecord = null; } /// /// Salva record ed avanza compilazione /// /// /// private async Task DoSave(OrderModel updRec) { // salvo record await OrdService.UpsertAsync(updRec); // cambio step CompileStep nextStep = currStep < CompileStep.FinalCheck ? currStep + 1 : currStep; AdvStep(nextStep); } /// /// Path da parent record /// /// /// private string FolderPath(int objID) { return $"SO-{objID:X8}"; } /// /// Rilegge tabella /// private async Task ForceReload() { isLoading = true; await Task.Delay(50); await ReloadDataAsync(); await Task.Delay(50); UpdateTable(); await Task.Delay(50); isLoading = false; await Task.Delay(50); } /// /// Modalità gestione code calcolo + display history /// /// private async Task ManageCalcReq(OrderModel? currRec) { EditStateRec = currRec; OrderHist = currRec != null ? currRec.LogHistory : new List(); if (currRec != null) { await UpdateJobQueue(currRec.Envir); } } /// /// Rilettura info di base /// /// private async Task ReloadBaseData() { AllConfEnvir = await EPService.GetAllAsync(); } /// /// Legge i dati dei record completi /// private async Task ReloadDataAsync() { AllRecords = await OrdService.GetFiltAsync(PeriodoSel.Inizio, PeriodoSel.Fine); DoFilter(); } private async Task ResetQueue(string args) { switch (args) { case "Run": await ResetRunQueue(); break; case "Wait": await ResetWaitQueue(); break; default: break; } } private void SaveNumRec(int newNum) { numRecord = newNum; currPage = 1; UpdateTable(); } private void SavePage(int newNum) { currPage = newNum; UpdateTable(); } /// /// Imposta periodo da filtro /// /// /// private async Task SetPeriodo(EgwCoreLib.Utils.DtUtils.Periodo newPeriod) { PeriodoSel = newPeriod; await ReloadDataAsync(); UpdateTable(); } private void SetupArrows() { listBord01 = new(); listBord01.Add(""); listBord01.Add("White"); listBord01.Add(""); listBord01.Add(""); } private async Task UpdateJobQueue(EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS envir) { // aggiorno coda corrente x display... var currQueueWait = await PService.QueueListAllAsync(envir, ProdQueueType.waiting); var currQueueRun = await PService.QueueListAllAsync(envir, ProdQueueType.running); var currQueueDone = await PService.QueueListAllAsync(envir, ProdQueueType.done); // converto x display... JobQueueWait = currQueueWait.Select(x => $"{x}").ToList(); JobQueueRun = currQueueRun.Select(x => $"{x}").ToList(); JobQueueDone = currQueueDone.Select(x => $"{x}").ToList(); // inverto ordine delle liste! JobQueueWait.Reverse(); JobQueueRun.Reverse(); JobQueueDone.Reverse(); } /// /// Filtro e paginazione /// private void UpdateTable() { // fix paginazione ListRecords = ListFilt .OrderByDescending(n => n.Inserted) .Skip(numRecord * (currPage - 1)) .Take(numRecord) .ToList(); } private void DoAction(string args) { if (args == "EditRow") { EditRecord = SelRecord; } } /// /// Prepara URL x download report /// /// /// /// /// private string DownloadOrdineUrl(int currId, string RepType = "Ordine", string SelFile = "Ordine_01") { return $"{apiUrl}/download?ReqId={currId}&RepType={RepType}&SelFile={SelFile}.repx"; } /// /// Prepara URL x download report /// /// /// /// /// private string DownloadMatUrl(int currId, string RepType = "MaterialReqOrd", string SelFile = "MaterialReqOrd_01") { return $"{apiUrl}/download?ReqId={currId}&RepType={RepType}&SelFile={SelFile}.repx"; } private bool selectOptPrint = false; private bool selectOptMatPrint = false; private int currId = 0; private void SelectOptPrint(int reqId) { selectOptPrint = true; currId = reqId; } private void SelectOptMatPrint(int reqId) { selectOptMatPrint = true; currId = reqId; } /// /// Ritorno step Tree /// /// private void ClosePrintModal(bool args) { selectOptPrint = false; selectOptMatPrint = false; } private string ButtonStateCss(OrderModel item) { string ans = ""; switch (item.OrderState) { case OrderStates.Created: ans = "secondary"; break; case OrderStates.Estimated: ans = "info"; break; case OrderStates.Assigned: ans = "info"; break; case OrderStates.ProdOdlCreated: ans = "info"; break; case OrderStates.Planned: ans = "info"; break; case OrderStates.Running: ans = "info"; break; case OrderStates.Completed: ans = "info"; break; case OrderStates.Delivered: ans = "success"; break; case OrderStates.Closed: ans = "success"; break; } return ans; } private string btnResetCss { get => string.IsNullOrEmpty(searchVal) ? "btn-outline-secondary" : "btn-primary"; } private void ResetSearch() { SearchVal = ""; } private string SearchVal { get => searchVal; set { if (searchVal != value) { searchVal = value; DoFilter(); UpdateTable(); } } } #endregion Private Methods } }