using EgwCoreLib.Lux.Core; using EgwCoreLib.Lux.Core.Generic; using EgwCoreLib.Lux.Core.RestPayload; using EgwCoreLib.Lux.Data; using EgwCoreLib.Lux.Data.DbModel.Config; using EgwCoreLib.Lux.Data.DbModel.Sales; using EgwCoreLib.Lux.Data.Services; using EgwCoreLib.Razor; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.JSInterop; using Newtonsoft.Json; using NLog.LayoutRenderers; using StackExchange.Redis; using static EgwCoreLib.Lux.Core.Enums; namespace Lux.UI.Components.Pages { public partial class Offers { #region Protected Enums /// /// Stato compilazione offerta /// protected enum CompileStep { Draft = 0, Header = 1, General, Rows, Delivery, FinalCheck } #endregion Protected Enums #region Protected Properties /// /// Filtro offerte: ogni stato / sole aperte /// protected bool AllStates { get => allState; set { if (allState != value) { allState = value; DoFilter(); UpdateTable(); } } } [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!; [Inject] protected IJSRuntime JSRuntime { get; set; } = null!; [Inject] protected ProdService PService { get; set; } = null!; protected string txtState { get => allState ? "Tutte" : "Aperte"; } #endregion Protected Properties #region Protected Methods protected string CheckSelect(OfferModel curRec) { string answ = ""; if (SelRecord != null) { answ = curRec.OfferID == SelRecord.OfferID ? "table-info" : ""; } return answ; } protected void DoAdd() { EditRecord = new OfferModel() { RefYear = DateTime.Today.Year, Description = $"Nuova Offerta {DateTime.Today:ddd yyyy.MM.dd}", ValidUntil = DateTime.Today.AddMonths(1) }; } protected async Task DoClone(OfferModel rec2clone) { if (!await JSRuntime.InvokeAsync("confirm", $"Confermi di voler duplicare interamente l'offerta selezionata?{Environment.NewLine}---------------------------{Environment.NewLine}Env: {rec2clone.Envir} | {rec2clone.OfferCode}{Environment.NewLine}{rec2clone.Description}{Environment.NewLine}Articoli: {rec2clone.NumItems}{Environment.NewLine}---------------------------{Environment.NewLine}Importo: {rec2clone.TotalPrice:C2}")) return; // clona intera offerta + tutte le righe... await DLService.OfferClone(rec2clone); await ReloadData(); UpdateTable(); } protected void DoEdit(OfferModel curRec) { currStep = CompileStep.Header; EditRecord = curRec; } protected void DoReset() { EditRecord = null; SelRecord = null; } protected void DoSelect(OfferModel 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(); } protected void SaveNumRec(int newNum) { numRecord = newNum; UpdateTable(); } protected void SavePage(int newNum) { currPage = newNum; UpdateTable(); } /// /// Imposta lo stato dell'offerta VERIFICANDO i vari casi di stato di artenza/arrivo... /// /// /// /// protected async Task SetState(OfferModel currRec, OfferStates newStatus) { /* --------------------------------- * se lo conferma: esegue step speciali come * - generazione item prod con ID ed etichetta * - generazione delle "buste di stima" x richiedere task stima preliminare * - generazione della lista delle etichette + riga d'ordine da inviare * - invio chiamata su channelRedis * * il puro invio dovrà poter essere fatto anche dalla tab ordini... e serve visualizzazione delle estim pending * --------------------------------- */ // in primis: se è già confermata chiede una autorizzazione di conferma speciale if (currRec.OffertState == OfferStates.Confirmed) { if (!await JSRuntime.InvokeAsync("confirm", $"Confermi di voler modificare l'offerta già confermata?")) return; } // se va verso conferma ricorda che ora l'ordine passa in pianificazione (carico macchine) if (newStatus == OfferStates.Confirmed) { if (!await JSRuntime.InvokeAsync("confirm", $"Confermi di voler confermare l'offerta e generare gli ordini? verranno generate anche le etichette per tutti i prodotti correlati ({currRec.NumProdItems})")) return; // creazione nuovo ordine da offerta var newOrd = await DLService.OrderFromOffer(currRec); if (newOrd != null) { // processo riga ordine x riga ordine creando per ogni riga una richiesta... if (newOrd.OrderRowNav != null && newOrd.OrderRowNav.Count > 0) { // verifico parametri da conf envir... var envRec = AllConfEnvir.FirstOrDefault(x => x.EnvirID == newOrd.Envir); Egw.Window.Data.Enums.QuestionModes cMode = Egw.Window.Data.Enums.QuestionModes.ORDER; Egw.Window.Data.Enums.QuestionOrderSubModes cSubMode = Egw.Window.Data.Enums.QuestionOrderSubModes.CREATE; string reqKey = ""; foreach (var rigaOrd in newOrd.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 TagList = ProdList.Select(x => x.ProdLabel).ToList(); //string serTagList = JsonConvert.SerializeObject(TagList); string serTagList = string.Join(",", TagList); // preparo richiesta serializzata e la accodo (viene inviata richiesta calcolo) Dictionary dictArgs = new Dictionary(); // compongo righiesta dictArgs.Add("UID", rigaOrd.OrderRowUID); // creo registrazione richiesta... var ruid = await CRService.AddRequestAsync($"{newOrd.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 (newOrd.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-{newOrd.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) { // mando richiesta "create" preliminare con tutti i dati dictArgs.Add("SubMode", $"{(int)cSubMode}"); calcReq = new CalcRequestDTO() { DictExec = dictArgs, EnvType = newOrd.Envir }; reqKey = $"{cMode}:{cSubMode}:{rigaOrd.OrderRowUID}"; await PService.EnqueueRequest("Estimation", reqKey, calcReq); // parto dalla history attuale var currHist = newOrd.LogHistory; // aggiungo evento... currHist.Add(new TaskHistDTO() { DtEvent = DateTime.Now, UserName = "Default User", Message = $"{reqKey}", IconCss = "fa-solid fa-hourglass-start" }); newOrd.LogHistory = currHist; //OrderHist = listOrdRow.LogHistory; await DLService.OrderUpsert(newOrd); } } } } } currRec.OffertState = newStatus; await DLService.OffertUpsert(currRec); await ReloadData(); UpdateTable(); } #endregion Protected Methods #region Private Fields private List AllConfEnvir = new(); private List AllRecords = new List(); private bool allState = false; /// /// Base path x network share files /// private string basePath = "unsafe_uploads"; private int currPage = 1; private CompileStep currStep = CompileStep.Draft; private OfferModel? EditRecord = null; private OfferModel? EditStateRec = null; private bool isLoading = false; private List ListFilt = new List(); private List ListRecords = new List(); private int numRecord = 10; /// /// Periodo selezionato attuale /// private EgwCoreLib.Utils.DtUtils.Periodo PeriodoSel = new EgwCoreLib.Utils.DtUtils.Periodo(EgwCoreLib.Utils.DtUtils.PeriodSet.ThisYear); private string searchVal = ""; private OfferModel? 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 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 => x.OffertState == OfferStates.Open || allState) .ToList(); if (!string.IsNullOrEmpty(searchVal)) { ListFilt = ListFilt .Where(x => x.Description.Contains(searchVal, StringComparison.InvariantCultureIgnoreCase) || x.OfferCode.Contains(searchVal, StringComparison.InvariantCultureIgnoreCase)) .ToList(); } totalCount = ListFilt.Count(); } /// /// Salva record ed avanza compilazione /// /// /// private async Task DoSave(OfferModel updRec) { // salvo record await DLService.OffertUpsert(updRec); // cambio step CompileStep nextStep = currStep < CompileStep.FinalCheck ? currStep + 1 : currStep; AdvStep(nextStep); } private void EditState(OfferModel? curRec) { EditStateRec = curRec; } /// /// 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); } /// /// 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.OfferGetAll(); AllRecords = await DLService.OfferGetFilt(PeriodoSel.Inizio, PeriodoSel.Fine); DoFilter(); } /// /// 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(""); } /// /// Filtro e paginazione /// private void UpdateTable() { // fix paginazione ListRecords = ListFilt .Skip(numRecord * (currPage - 1)) .Take(numRecord) .ToList(); } #endregion Private Methods #if false protected void SetNumRec(int newNum) { numRecord = newNum; RefreshDisplay(); } protected void SetPage(int newNum) { currPage = newNum; RefreshDisplay(); } protected void SortRequested(Sorter.SortCallBack e) { if (sortField == e.ParamName) { sortAsc = e.IsAscending; } sortField = e.ParamName; RefreshDisplay(); } #endif } }