using EgwCoreLib.Lux.Core; using EgwCoreLib.Lux.Core.Generic; using EgwCoreLib.Lux.Core.RestPayload; using EgwCoreLib.Lux.Data.DbModel.Config; using EgwCoreLib.Lux.Data.DbModel.Sales; using EgwCoreLib.Lux.Data.Services; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.JSInterop; using NLog; 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 Properties [Inject] protected IConfiguration Config { get; set; } = null!; [Inject] protected CalcRuidService CRService { get; set; } = null!; protected string DivMainCss { get => SelRecord != null ? "col-6" : "col-12"; } [Inject] protected DataLayerServices DLService { get; set; } = null!; /// /// Filtro stato ordini /// protected Enums.OrderStates? FiltState { get => filtState; set { if (filtState != value) { filtState = value; DoFilter(); UpdateTable(); } } } [Inject] protected IJSRuntime JSRuntime { get; set; } = null!; [Inject] protected ProdService PService { get; set; } = null!; #endregion Protected Properties #region Protected Methods protected string CheckSelect(OrderModel curRec) { string answ = ""; if (SelRecord != null) { answ = curRec.OfferID == SelRecord.OfferID ? "table-info" : ""; } return answ; } protected void DoAdd() { EditRecord = new OrderModel() { RefYear = DateTime.Today.Year, Description = $"Nuova Offerta {DateTime.Today:ddd yyyy.MM.dd}", ValidUntil = DateTime.Today.AddMonths(1) }; } protected void DoEdit(OrderModel curRec) { currStep = CompileStep.Header; EditRecord = curRec; } protected void DoReset() { EditRecord = null; SelRecord = null; } protected 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 ReloadData(); UpdateTable(); } /// /// Rimette un Job da coda running in waiting /// /// protected async Task ReRunJob(string? JobCode) { if (!string.IsNullOrEmpty(JobCode)) { if (!await JSRuntime.InvokeAsync("confirm", $"Sicuro di voler rimettere in coda il calcolo?")) return; await PService.ReRunJob(JobCode); await UpdateJobQueue(); } } /// /// Reseet History dell'ordine /// /// /// protected async Task ResetHistory(OrderModel currRec) { if (!await JSRuntime.InvokeAsync("confirm", $"Sicuro di voler resettare l'history dell'ordine corrente? L'operazione non è revertibile.")) return; currRec.LogHistory = new List(); OrderHist = currRec.LogHistory; await DLService.OrderUpsert(currRec); } /// /// Resetta coda running riportandoli in waiting /// /// protected async Task ResetRunQueue() { if (!await JSRuntime.InvokeAsync("confirm", $"Sicuro di voler resettarela coda di run calcolo? Le richieste verranno riaccodate in waiting.")) return; await PService.ResetRunning(); await UpdateJobQueue(); } /// /// Resetta coda waiting eliminando task /// /// protected async Task ResetWaitQueue() { if (!await JSRuntime.InvokeAsync("confirm", $"Sicuro di voler resettarela coda di attesa calcolo eliminando le richieste in attesa? L'operazione non è revertibile.")) return; await PService.QueueResetAsync(ProdService.QueueType.waiting); await UpdateJobQueue(); } /// /// Manda l'ordine in fase di estimation /// /// protected 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.. * --------------------------------- */ if (!await JSRuntime.InvokeAsync("confirm", $"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.")) 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 = ""; 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 var ProdList = await DLService.ProdItemByOrderRow(rigaOrd.OrderRowID); List TagsList = ProdList.Select(x => x.ProdLabel).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); dictArgs.Add("OrderUID", rigaOrd.OrderNav.OrderCode); 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 = $"SO-{currRec.OfferID:X8}"; 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) { // tolta richiesta create #if false // mando richiesta "create" preliminare con tutti i dati cSubMode = Egw.Window.Data.Enums.QuestionOrderSubModes.CREATE; dictArgs.Add("SubMode", $"{(int)cSubMode}"); calcReq = new CalcRequestDTO() { DictExec = dictArgs, EnvType = currRec.Envir }; reqKey = $"{cMode}:{cSubMode}:{rigaOrd.OrderRowUID}"; await PService.EnqueueRequest("Estimation", reqKey, calcReq); #endif // 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.EnqueueRequest("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 DLService.OrderUpsert(currRec); } } } await UpdateJobQueue(); } #endregion Protected Methods #region Private Fields 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 string txtStyle = "font-size: 1.2em; font-weight:bold; fill: white;"; #endregion Private Fields #region Private Properties private Enums.OrderStates? filtState { get; set; } = null; private List listBord01 { get; set; } = new(); #endregion Private Properties #region Private Methods 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"; } private void DoClose() { EditRecord = null; } private void DoFilter() { // verifico eventuali filtri ListFilt = AllRecords .Where(x => filtState == null || x.OrderState == filtState) .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(); } /// /// Salva record ed avanza compilazione /// /// /// private async Task DoSave(OrderModel updRec) { // salvo record await DLService.OrderUpsert(updRec); // cambio step CompileStep nextStep = currStep < CompileStep.FinalCheck ? currStep + 1 : currStep; AdvStep(nextStep); } /// /// Rilegge tabella /// private async Task ForceReload() { isLoading = true; await Task.Delay(50); await ReloadData(); await Task.Delay(50); UpdateTable(); await Task.Delay(50); isLoading = false; await Task.Delay(50); } #if false /// /// Restituisce il contenuto del file salvato /// /// /// /// private string LoadFileContent(string folderPath, string secureName) { string answ = ""; if (!string.IsNullOrEmpty(folderPath)) { try { // calcolo path file... string filePath = Path.Combine(basePath, folderPath, secureName); if (File.Exists(filePath)) { answ = File.ReadAllText(filePath); } } catch (Exception exc) { Log.Error($"Exception on LoadFileContent{Environment.NewLine}{exc}"); } } return answ; } #endif /// /// Modalità gestione code calcolo + display history /// /// private async Task ManageCalcReq(OrderModel? curRec) { EditStateRec = curRec; OrderHist = curRec != null ? curRec.LogHistory : new List(); await UpdateJobQueue(); } /// /// Rilettura info di base /// /// private async Task ReloadBaseData() { AllConfEnvir = await DLService.ConfEnvirParamGetAllAsync(); } /// /// Legge i dati dei record completi /// private async Task ReloadData() { await DLService.OffersCheckExpired(); AllRecords = await DLService.OrderGetFilt(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; } } /// /// Imposta periodo da filtro /// /// /// private async Task SetPeriodo(EgwCoreLib.Utils.DtUtils.Periodo newPeriod) { PeriodoSel = newPeriod; await ReloadData(); UpdateTable(); } private void SetupArrows() { listBord01 = new(); listBord01.Add(""); listBord01.Add("White"); listBord01.Add(""); listBord01.Add(""); } private async Task UpdateJobQueue() { // aggiorno coda corrente x display... var currQueueWait = await PService.QueueListAllAsync(ProdService.QueueType.waiting); var currQueueRun = await PService.QueueListAllAsync(ProdService.QueueType.running); var currQueueDone = await PService.QueueListAllAsync(ProdService.QueueType.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 .Skip(numRecord * (currPage - 1)) .Take(numRecord) .ToList(); } #endregion Private Methods } }