using EgwCoreLib.Lux.Core.Generic; using EgwCoreLib.Razor; using static EgwCoreLib.Lux.Core.Enums; namespace Lux.UI.Components.Pages { public partial class Offers { #region Protected Properties /// /// Filtro offerte: ogni stato / sole aperte /// protected bool AllStates { get => allState; set { if (allState != value) { allState = value; DoFilter(); UpdateTable(); } } } private List OfferStateList { get => Enum.GetNames(typeof(Enums.OfferStates)) .ToList(); } private Enums.OfferStates? filtState { get; set; } = null; private Enums.OfferStates? 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(); } } } #endregion Protected Properties #region Protected Methods protected override async Task OnInitializedAsync() { // prendo il trim corrente + anno precedente... PeriodoSel = new DtUtils.Periodo(DtUtils.PeriodSet.ThisTrim); PeriodoSel.Inizio = PeriodoSel.Inizio.AddYears(-1); SetupArrows(); ConfInit(); await ReloadBaseData(); await ReloadDataAsync(); UpdateTable(); } 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 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 List ListChanges = new(); private int numRecord = 10; /// /// Periodo selezionato attuale /// private DtUtils.Periodo PeriodoSel = new DtUtils.Periodo(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;"; private BootstrapModal Modal = new(); private string mTitle = ""; private string mMessage = ""; private BootstrapModal.ModalMode mMode = BootstrapModal.ModalMode.ND; private Dictionary modalOpt = new(); private Dictionary selectOpt = new(); /// /// Periodo custom selezione valori /// private Dictionary? CustomSelDict = new(); #endregion Private Fields #region Private Properties [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 IEnvirParamService EPService { get; set; } = null!; [Inject] private IJSRuntime JSRuntime { get; set; } = null!; private List listBord01 { get; set; } = new(); [Inject] private IOfferService OffService { get; set; } = default!; [Inject] private IOrderService OrdService { get; set; } = default!; [Inject] private IProductionItemService PIService { get; set; } = default!; [Inject] private IProdService PService { get; set; } = null!; [Inject] private NavigationManager NavigationManager { get; set; } = null!; private string txtState { get => allState ? "Tutte" : "Aperte"; } private string apiUrl = ""; #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 string CheckSelect(OfferModel curRec) { string answ = ""; if (SelRecord != null) { answ = curRec.OfferID == SelRecord.OfferID ? "table-info" : ""; } return answ; } private void ConfInit() { basePath = Config.GetValue("ServerConf:FileSharePath") ?? "unsafe_uploads"; apiUrl = Config.GetValue("ServerConf:ReportUrl") ?? ""; } private void DoAction(string args) { if (args == "EditRow") { currStep = CompileStep.Rows; EditRecord = SelRecord; } } private async Task DoAdd() { mTitle = "Selezionare Environment"; mMode = BootstrapModal.ModalMode.Select; selectOpt = new(); foreach (var item in Enum.GetValues()) { if (item != EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.NULL) selectOpt.Add($"{(int)item}", $"{item}"); } modalOpt = new(); string? sEnv = await Modal!.ShowAsync(); if (string.IsNullOrEmpty(sEnv)) return; // calcolo envir... if (Enum.TryParse(sEnv, out EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS cEnv)) { int refNum = AllRecords.Where(x => x.RefYear == DateTime.Today.Year).Max(x => x.RefNum) + 1; EditRecord = new OfferModel() { Envir = cEnv, RefYear = DateTime.Today.Year, RefNum = refNum, Inserted = DateTime.Today, Description = $"Nuova Offerta {DateTime.Today:ddd yyyy.MM.dd}", ValidUntil = DateTime.Today.AddMonths(1) }; currStep = CompileStep.Header; } } private async Task DoClone(OfferModel rec2clone) { mTitle = "Attenzione"; mMessage = "Confermi di voler duplicare interamente l'offerta selezionata?"; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; // clona intera offerta + tutte le righe... await OffService.CloneAsync(rec2clone); await ReloadDataAsync(); UpdateTable(); } private async Task DoCancel() { int prevId = EditRecord?.OfferID ?? 0; EditRecord = null; await ReloadDataAsync(); await Task.Delay(10); EditRecord = ListRecords.FirstOrDefault(x => x.OfferID == prevId); } private void DoEdit(OfferModel curRec) { currStep = CompileStep.Header; EditRecord = curRec; } private async Task DoEsc() { // chiudo offerta se confermo mTitle = "Chiusura"; mMessage = "Confermi di voler uscire dall'offerta corrente?"; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; EditRecord = null; SelRecord = null; } private void DoReset() { EditRecord = null; SelRecord = null; } private void DoFilter() { ListFilt = AllRecords .Where(x => (filtState == null || x.OffertState == FiltState) && (filtEnv == EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.NULL || x.Envir == FiltEnv)) .ToList(); //// 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(); currPage = 1; SelRecord = null; } /// /// Salva record ed avanza compilazione /// /// /// private async Task DoSave(OfferModel updRec) { // aggiongo dataora modifica forzata... updRec.Modified = DateTime.Now; // salvo record await OffService.UpsertAsync(updRec); // cambio step CompileStep nextStep = new CompileStep(); if (currStep < CompileStep.Delivery) { // se NON window e passasse da testata deve saltare generale... if (updRec.Envir != EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW && currStep == CompileStep.Header) { nextStep = currStep + 2; } else { nextStep = currStep + 1; } AdvStep(nextStep); } else { EditRecord = null; } } private void DoSelect(OfferModel curRec) { SelRecord = curRec; } private void EditState(OfferModel? curRec) { EditStateRec = curRec; } /// /// 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); } /// /// Rilettura info di base /// /// private async Task ReloadBaseData() { AllConfEnvir = await EPService.GetAllAsync(); } /// /// Legge i dati dei record completi /// private async Task ReloadDataAsync() { await OffService.CheckExpiredAsync(); AllRecords = await OffService.GetFiltAsync(PeriodoSel.Inizio, PeriodoSel.Fine); DoFilter(); } private void SaveNumRec(int newNum) { numRecord = newNum; UpdateTable(); } private void SavePage(int newNum) { currPage = newNum; UpdateTable(); } private void SetDirty(EditStepDto updData) { #if false // semodificato imposto colore variato x header if (updData.Changed) { if (!ListtChanges.Contains(updData.SrcStep)) { ListtChanges.Add(updData.SrcStep); } } else { if (ListtChanges.Contains(updData.SrcStep)) { ListtChanges.Remove(updData.SrcStep); } } #endif } /// /// Imposta periodo da filtro /// /// /// private async Task SetPeriodo(DtUtils.Periodo newPeriod) { PeriodoSel = newPeriod; await ReloadDataAsync(); UpdateTable(); } /// /// Imposta lo stato dell'offerta VERIFICANDO i vari casi di stato di artenza/arrivo... /// /// /// /// private 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) { mTitle = "Conferma"; mMessage = "Confermi di voler modificare l'offerta già confermata?"; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; } // se va verso conferma ricorda che ora l'ordine passa in pianificazione (carico macchine) if (newStatus == OfferStates.Confirmed) { mTitle = "Conferma"; mMessage = $"Sei sicuro di voler confermare l'offerta e generare gli ordini? verranno generate anche le etichette per tutti i prodotti correlati ({currRec.NumProdItems})"; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; // creazione nuovo ordine da offerta var newOrd = await OrdService.CloneOfferAsync(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 PIService.GetByOrderRowAsync(rigaOrd.OrderRowID); List TagList = ProdList.Select(x => x.ProdItemTag ?? "").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 = FolderPath(newOrd.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) { // 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.EnqueueRequestAsync("Create", 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 OrdService.UpsertAsync(newOrd); } } } } } currRec.OffertState = newStatus; await OffService.UpsertAsync(currRec); await ReloadDataAsync(); 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 .OrderByDescending(n => n.Inserted) .Skip(numRecord * (currPage - 1)) .Take(numRecord) .ToList(); } /// /// Prepara URL x download report /// /// /// /// /// private string DownloadUrl(int currId, string repType = "Offerta", string SelFile = "Offerta_01") { return $"{apiUrl}/download?ReqId={currId}&RepType={repType}&SelFile={SelFile}.repx"; } private bool selectOptPrint = false; private int currId = 0; private void SelectOptPrint(int reqId) { selectOptPrint = true; currId = reqId; } /// /// Ritorno step Tree /// /// private void ClosePrintModal(bool args) { selectOptPrint = false; } private string ButtonStateCss(OfferModel item) { string ans = ""; switch (item.OffertState) { case OfferStates.Open: ans = "info"; break; case OfferStates.Confirmed: ans = "success"; break; case OfferStates.Expired: ans = "warning"; break; case OfferStates.Lost: ans = "danger"; 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 } }