diff --git a/EgwCoreLib.Lux.Core/RestPayload/EstimReqPayloadDTO.cs b/EgwCoreLib.Lux.Core/RestPayload/EstimReqPayloadDTO.cs new file mode 100644 index 00000000..5454954e --- /dev/null +++ b/EgwCoreLib.Lux.Core/RestPayload/EstimReqPayloadDTO.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EgwCoreLib.Lux.Core.RestPayload +{ + /// + /// Classe DTO x richieste di stima lavorazioni + /// + public class EstimReqPayloadDTO + { + /// + /// UID Richiesta + /// + public string TaskUID { get; set; } = ""; + +#if false + /// + /// Batch di produzione di riferimento + /// + public int ProductionBatchID { get; set; } = 0; + + /// + /// ID Ordine di origine + /// + public int OrderID { get; set; } = 0; + + /// + /// ID univoco riga ordine + /// + public int OrderRowID { get; set; } = 0; +#endif + + /// + /// Filename (ove presente) + /// + public string FileName { get; set; } = ""; + + /// + /// Valore serializzato dell'item della riga d'ordine + /// + public string SerializedData { get; set; } = ""; + + /// + /// Dizionario delle tags/etichette da associare ad ogni pezzo contenuto nella richiesta (da ItemQty della BOM) + /// - key: UID Tag dell'item da produrre (etichetta UID) + /// - value: UID della riga ordine di provenienza (raggruppamento) + /// + public Dictionary ItemTagList { get; set; } = new Dictionary(); + } +} diff --git a/EgwCoreLib.Lux.Core/RestPayload/NestingReqPayloadDTO.cs b/EgwCoreLib.Lux.Core/RestPayload/NestingReqPayloadDTO.cs new file mode 100644 index 00000000..58e89e49 --- /dev/null +++ b/EgwCoreLib.Lux.Core/RestPayload/NestingReqPayloadDTO.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EgwCoreLib.Lux.Core.RestPayload +{ + public class NestingReqPayloadDTO + { + } +} diff --git a/EgwCoreLib.Lux.Data/Controllers/LuxController.cs b/EgwCoreLib.Lux.Data/Controllers/LuxController.cs index 4b825be5..572ae382 100644 --- a/EgwCoreLib.Lux.Data/Controllers/LuxController.cs +++ b/EgwCoreLib.Lux.Data/Controllers/LuxController.cs @@ -1494,6 +1494,65 @@ namespace EgwCoreLib.Lux.Data.Controllers return answ; } + /// + /// Upsert dell'elenco dei tags associati + /// + /// ID Job richiesto + /// Elenco Tags richiesto + /// + internal async Task JobTask2TagsUpsertAsync(int JobID, List reqTagList) + { + bool answ = false; + //using (DataLayerContext dbCtx = new DataLayerContext(_config)) + using (DataLayerContext dbCtx = new DataLayerContext()) + { + try + { + var currRec = dbCtx + .DbSetJobTask + .Where(x => x.JobID == JobID) + .Include(t => t.TagNav) + .FirstOrDefault(); + // se trovato --> aggiorno + if (currRec != null) + { + var currentTags = currRec.TagNav.Select(t => t.CodTag).ToList(); + + // calcolo modifiche + var toAdd = reqTagList.Except(currentTags).ToList(); + var toRemove = currentTags.Except(reqTagList).ToList(); + + // aggiunte + foreach (var tag in toAdd) + { + currRec.TagNav.Add(new JobTaskTagModel + { + JobID = JobID, + CodTag = tag + }); + } + // rimozioni + foreach (var tag in toRemove) + { + var entity = currRec.TagNav.FirstOrDefault(t => t.CodTag == tag); + if (entity != null) + dbCtx.Remove(entity); + } + + dbCtx.Entry(currRec).State = EntityState.Modified; + } + // salvo... + int numAct = await dbCtx.SaveChangesAsync(); + answ = numAct > 0; + } + catch (Exception exc) + { + Log.Error($"Eccezione durante JobTask2TagsUpsertAsync{Environment.NewLine}{exc}"); + } + } + return answ; + } + /// /// Eliminazione record richiesto /// @@ -1669,13 +1728,13 @@ namespace EgwCoreLib.Lux.Data.Controllers } return answ; } + /// - /// Upsert dell'elenco dei tags associati + /// esegue il cloning completo di un offerta e di TUTTE le relative righe di offerta... /// - /// ID Job richiesto - /// Elenco Tags richiesto + /// /// - internal async Task JobTask2TagsUpsertAsync(int JobID, List reqTagList) + internal async Task OfferClone(OfferModel rec2clone) { bool answ = false; //using (DataLayerContext dbCtx = new DataLayerContext(_config)) @@ -1683,46 +1742,83 @@ namespace EgwCoreLib.Lux.Data.Controllers { try { + // recupero offerta... var currRec = dbCtx - .DbSetJobTask - .Where(x => x.JobID == JobID) - .Include(t => t.TagNav) + .DbSetOffer + .Where(x => x.OfferID == rec2clone.OfferID) + .Include(x => x.OfferRowNav) .FirstOrDefault(); - // se trovato --> aggiorno + + // se trovo --> duplico! if (currRec != null) { - var currentTags = currRec.TagNav.Select(t => t.CodTag).ToList(); - - // calcolo modifiche - var toAdd = reqTagList.Except(currentTags).ToList(); - var toRemove = currentTags.Except(reqTagList).ToList(); - - // aggiunte - foreach (var tag in toAdd) + DateTime adesso = DateTime.Now; + OfferModel newRec = new OfferModel() { - currRec.TagNav.Add(new JobTaskTagModel + ConsNote = rec2clone.ConsNote, + CustomerID = rec2clone.CustomerID, + DealerID = rec2clone.DealerID, + Description = rec2clone.Description, + DictPresel = rec2clone.DictPresel, + Discount = rec2clone.Discount, + DueDateProm = rec2clone.DueDateProm, + DueDateReq = rec2clone.DueDateReq, + Envir = rec2clone.Envir, + Inserted = adesso, + Modified = adesso, + OffertState = OfferStates.Open, + RefNum = rec2clone.RefNum, + RefRev = 0, + RefYear = adesso.Year, + ValidUntil = currRec.ValidUntil + }; + + // sistemo child... + newRec.OfferRowNav = currRec.OfferRowNav + .Select(c => new OfferRowModel() { - JobID = JobID, - CodTag = tag - }); - } - // rimozioni - foreach (var tag in toRemove) - { - var entity = currRec.TagNav.FirstOrDefault(t => t.CodTag == tag); - if (entity != null) - dbCtx.Remove(entity); - } + AwaitBom = c.AwaitBom, + AwaitPrice = c.AwaitPrice, + BomCost = c.BomCost, + BomOk = c.BomOk, + BomPrice = c.BomPrice, + Envir = c.Envir, + FileName = c.FileName, + FileResource = c.FileResource, + FileSize = c.FileSize, + Inserted = adesso, + ItemBOM = c.ItemBOM, + ItemJCD = c.ItemJCD, + ItemOk = c.ItemOk, + ItemSteps = c.ItemSteps, + ItemTags = c.ItemTags, + JobID = c.JobID, + Modified = c.Modified, + Note = c.Note, + Qty = c.Qty, + RowNum = c.RowNum, + SellingItemID = c.SellingItemID, + SerStruct = c.SerStruct, + StepCost = c.StepCost, + StepFlowTime = c.StepFlowTime, + StepLeadTime = c.StepLeadTime, + StepPrice = c.StepPrice, + //OfferID = newRec.OfferID, + OfferRowUID = c.OfferRowDtx + }) + .ToList(); - dbCtx.Entry(currRec).State = EntityState.Modified; + // infine aggiungo riga ordine e relativi child + dbCtx.DbSetOffer.Add(newRec); } - // salvo... - int numAct = await dbCtx.SaveChangesAsync(); - answ = numAct > 0; + + // salvo TUTTI i cambiamenti... + var result = await dbCtx.SaveChangesAsync(); + answ = result > 0; } catch (Exception exc) { - Log.Error($"Eccezione durante JobTask2TagsUpsertAsync{Environment.NewLine}{exc}"); + Log.Error($"Eccezione durante OfferClone{Environment.NewLine}{exc}"); } } return answ; @@ -1755,6 +1851,36 @@ namespace EgwCoreLib.Lux.Data.Controllers return dbResult; } + /// + /// Elenco offerte da DB filtrate x periodo e stato + /// + /// + /// + /// + internal async Task> OfferGetFilt(DateTime inizio, DateTime fine) + { + List dbResult = new List(); + //using (DataLayerContext dbCtx = new DataLayerContext(_config)) + using (DataLayerContext dbCtx = new DataLayerContext()) + { + try + { + dbResult = await dbCtx + .DbSetOffer + .Where(x => x.Inserted >= inizio && x.Inserted <= fine) + .Include(c => c.CustomerNav) + .Include(d => d.DealerNav) + .Include(o => o.OfferRowNav) + .ToListAsync(); + } + catch (Exception exc) + { + Log.Error($"Eccezione durante OfferGetFilt{Environment.NewLine}{exc}"); + } + } + return dbResult; + } + /// /// Elenco righe offerta specificata /// @@ -1811,6 +1937,46 @@ namespace EgwCoreLib.Lux.Data.Controllers return dbResult; } #endif + /// + /// Verifica e update offerte scadute + /// + /// + + internal async Task OffersCheckExpired() + { + bool answ = false; + //using (DataLayerContext dbCtx = new DataLayerContext(_config)) + using (DataLayerContext dbCtx = new DataLayerContext()) + { + try + { + DateTime adesso = DateTime.Now; + // recupero offerta... + var listExpired = dbCtx + .DbSetOffer + .Where(x => x.ValidUntil < adesso && x.OffertState == OfferStates.Open) + .ToList(); + + // se trovo le aggiorno come stato + if (listExpired != null) + { + foreach (var item in listExpired) + { + item.OffertState = OfferStates.Expired; + dbCtx.Entry(item).State = EntityState.Modified; + } + // salvo TUTTI i cambiamenti... + var result = await dbCtx.SaveChangesAsync(); + answ = result > 0; + } + } + catch (Exception exc) + { + Log.Error($"Eccezione durante OffersCheckExpired{Environment.NewLine}{exc}"); + } + } + return answ; + } /// /// Elimina riga e sposta eventuali righe successive... diff --git a/EgwCoreLib.Lux.Data/DbModel/Production/ProductionBatchModel.cs b/EgwCoreLib.Lux.Data/DbModel/Production/ProductionBatchModel.cs index 861240e1..24255d99 100644 --- a/EgwCoreLib.Lux.Data/DbModel/Production/ProductionBatchModel.cs +++ b/EgwCoreLib.Lux.Data/DbModel/Production/ProductionBatchModel.cs @@ -11,7 +11,7 @@ namespace EgwCoreLib.Lux.Data.DbModel.Production public class ProductionBatchModel { /// - /// ID dell'articolo + /// ID del Batch di produzione /// [Key] public int ProductionBatchID { get; set; } diff --git a/EgwCoreLib.Lux.Data/ModelBuilderExtensions.cs b/EgwCoreLib.Lux.Data/ModelBuilderExtensions.cs index a465df1c..18d0977d 100644 --- a/EgwCoreLib.Lux.Data/ModelBuilderExtensions.cs +++ b/EgwCoreLib.Lux.Data/ModelBuilderExtensions.cs @@ -335,10 +335,10 @@ namespace EgwCoreLib.Lux.Data // inizializzazione dei valori di default x Offer modelBuilder.Entity().HasData( - new OfferModel { OfferID = 1, RefYear = 2024, RefNum = 1, RefRev = 1, Description = "Offerta per tre serramenti", CustomerID = 2, DealerID = 2, Envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW }, - new OfferModel { OfferID = 2, RefYear = 2024, RefNum = 2, RefRev = 1, Description = "Offerta BEAM", CustomerID = 2, DealerID = 2, Envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.BEAM }, - new OfferModel { OfferID = 3, RefYear = 2024, RefNum = 3, RefRev = 1, Description = "Offerta Cabinet", CustomerID = 2, DealerID = 2, Envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.CABINET }, - new OfferModel { OfferID = 4, RefYear = 2024, RefNum = 4, RefRev = 1, Description = "Offerta Wall", CustomerID = 2, DealerID = 2, Envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WALL } + new OfferModel { OfferID = 1, RefYear = 2025, RefNum = 1, RefRev = 1, Description = "Offerta per tre serramenti", CustomerID = 2, DealerID = 2, Envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW }, + new OfferModel { OfferID = 2, RefYear = 2025, RefNum = 2, RefRev = 1, Description = "Offerta BEAM", CustomerID = 2, DealerID = 2, Envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.BEAM }, + new OfferModel { OfferID = 3, RefYear = 2025, RefNum = 3, RefRev = 1, Description = "Offerta Cabinet", CustomerID = 2, DealerID = 2, Envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.CABINET }, + new OfferModel { OfferID = 4, RefYear = 2025, RefNum = 4, RefRev = 1, Description = "Offerta Wall", CustomerID = 2, DealerID = 2, Envir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WALL } //new OfferModel { OfferID = 2, RefYear = 2025, RefNum = 2, RefRev = 1, Name = "Offerta per un serramento + installazione", CustomerID = 1, DealerID = 1 }, //new OfferModel { OfferID = 3, RefYear = 2025, RefNum = 3, RefRev = 1, Name = "Offerta per tre serramenti", CustomerID = 2, DealerID = 1 }, //new OfferModel { OfferID = 5, RefYear = 2025, RefNum = 4, RefRev = 2, Name = "Offerta per cinque serramenti + installazione", CustomerID = 3, DealerID = 2 } diff --git a/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs b/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs index 2fee2283..ea91c5ed 100644 --- a/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs +++ b/EgwCoreLib.Lux.Data/Services/DataLayerServices.cs @@ -827,6 +827,20 @@ namespace EgwCoreLib.Lux.Data.Services return result; } + /// + /// Esegue Upsert info Tag associati + /// + /// + /// + /// + public async Task JobTask2TagsUpsertAsync(int JobID, List reqTagList) + { + bool result = await dbController.JobTask2TagsUpsertAsync(JobID, reqTagList); + await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:JobTaskList:*"); + await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:JobStep:*"); + return result; + } + /// /// Esegue eliminazione + refresh cache /// @@ -903,17 +917,22 @@ namespace EgwCoreLib.Lux.Data.Services } /// - /// Esegue Upsert info Tag associati + /// Esegue clone completo dell'offerta indicata e svuota la cache /// - /// - /// + /// /// - public async Task JobTask2TagsUpsertAsync(int JobID, List reqTagList) + public async Task OfferClone(OfferModel rec2clone) { - bool result = await dbController.JobTask2TagsUpsertAsync(JobID, reqTagList); - await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:JobTaskList:*"); - await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:JobStep:*"); - return result; + Stopwatch sw = new Stopwatch(); + sw.Start(); + // calcolo + bool fatto = await dbController.OfferClone(rec2clone); + // svuoto cache... + await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:Offers:*"); + await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OfferRows:*"); + sw.Stop(); + Log.Debug($"OfferClone in {sw.Elapsed.TotalMilliseconds} ms"); + return fatto; } /// @@ -951,6 +970,42 @@ namespace EgwCoreLib.Lux.Data.Services return result; } + /// + /// Elenco offerte da DB filtrate x periodo e stato + /// + /// + /// + /// + public async Task> OfferGetFilt(DateTime inizio, DateTime fine) + { + string source = "DB"; + Stopwatch sw = new Stopwatch(); + sw.Start(); + List? result = new List(); + // cerco in redis... + string currKey = $"{redisBaseKey}:Offers:Filt:{inizio:yyMMdd-HHmm}:{fine:yyMMdd-HHmm}"; + RedisValue rawData = await redisDb.StringGetAsync(currKey); + if (rawData.HasValue) + { + result = JsonConvert.DeserializeObject>($"{rawData}"); + source = "REDIS"; + } + else + { + result = await dbController.OfferGetFilt(inizio, fine); + // serializzo e salvo con config x evitare loop... + rawData = JsonConvert.SerializeObject(result, JSSettings); + await redisDb.StringSetAsync(currKey, rawData, LongCache); + } + if (result == null) + { + result = new List(); + } + sw.Stop(); + Log.Debug($"OfferGetFilt | {source} | {sw.Elapsed.TotalMilliseconds}ms"); + return result; + } + /// /// Elenco righe offerta specificata /// @@ -1007,6 +1062,23 @@ namespace EgwCoreLib.Lux.Data.Services } #endif + /// + /// Verifica offerte scadute, con update sul DB + /// + public async Task OffersCheckExpired() + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + // calcolo + bool fatto = await dbController.OffersCheckExpired(); + // svuoto cache... + await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:Offers:*"); + await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:OfferRows:*"); + sw.Stop(); + Log.Debug($"OffersCheckExpired in {sw.Elapsed.TotalMilliseconds} ms"); + return fatto; + } + /// /// Converte il campo raw della BOM in lista oggetti da gestire /// diff --git a/Lux.API/Controllers/ProdController.cs b/Lux.API/Controllers/ProdController.cs new file mode 100644 index 00000000..1f2887d6 --- /dev/null +++ b/Lux.API/Controllers/ProdController.cs @@ -0,0 +1,87 @@ +using EgwCoreLib.Lux.Core.RestPayload; +using EgwCoreLib.Lux.Data; +using EgwCoreLib.Lux.Data.DbModel.Config; +using EgwCoreLib.Lux.Data.Services; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; +using NLog; +using System.Diagnostics; + +namespace Lux.API.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class ProdController : ControllerBase + { + #region Public Constructors + + public ProdController(IConfiguration config, IRedisService redisService, ImageCacheService imgServ) + { + _config = config; + _redisService = redisService; + chPub = _config.GetValue("ServerConf:ChannelPub") ?? ""; + } + + #endregion Public Constructors + + #region Public Methods + + /// + /// Chiamata GET: test status alive + /// GET: api/Prod/alive + /// + /// id oggetto + /// + [HttpGet("alive")] + public async Task Alive() + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + await Task.Delay(1); + sw.Stop(); + Log.Info($"Alive | {sw.Elapsed.TotalMilliseconds:N3} ms"); + return Ok("OK"); + } + + /// + /// Chiamata GET: + /// - elenco delle richieste di stima da eseguire + /// - vengono registrate come "passate" al calcolo alla data-ora della richiesta + /// GET: api/Prod/estimation + /// + /// + [HttpGet("estimation")] + public async Task>> EstimationRequestQueue() + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + var listReq = new List(); + // vado a recuperare da REDIS elenco degli ordini NON ancora associati ad 1/+ prod + + // opzione 1: restituisco TUTTI ordini NON ancora eseguiti + // opzione 2: restituisco dall'inizio solo max(n) non ancora eseguiti? (es primi 5 ordini) + + // genero elenco degli ordini e per ogni ordine aggiungo il Dict + await Task.Delay(100); + + // opzione 1: per tutti gli ordini ritornato registro data-ora invio e tolgo dalla coda... + // opzione 2: aspetto conferma dal sistema che li ha presi in carico e registro data-ora... + + sw.Stop(); + Log.Info($"EstimationRequestQueue | {sw.Elapsed.TotalMilliseconds:N3} ms"); + return Ok(listReq); + } + + #endregion Public Methods + + #region Private Fields + + private static Logger Log = LogManager.GetCurrentClassLogger(); + private readonly IRedisService _redisService; + private readonly string chPub = ""; + private IConfiguration _config; + + #endregion Private Fields + } +} \ No newline at end of file diff --git a/Lux.API/Lux.API.csproj b/Lux.API/Lux.API.csproj index 199a7ebe..b53ea3d9 100644 --- a/Lux.API/Lux.API.csproj +++ b/Lux.API/Lux.API.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - 0.9.2511.1312 + 0.9.2511.1416 diff --git a/Lux.UI/Components/Layout/NavMenu.razor b/Lux.UI/Components/Layout/NavMenu.razor index 8b55b4a6..65a47932 100644 --- a/Lux.UI/Components/Layout/NavMenu.razor +++ b/Lux.UI/Components/Layout/NavMenu.razor @@ -54,6 +54,11 @@ Offerte + -
@@ -78,6 +75,30 @@ } else { + if (EditStateRec != null) + { + + }
@@ -85,7 +106,24 @@ else Offerte
- Periodo | ricerca testo +
+
+ +
+
+
+ @* Stato *@ +
+
+ + +
+
+ + +
+
+
@@ -110,6 +148,8 @@ else ID + Date + Stato Codice Agente/Riv Cliente @@ -129,10 +169,17 @@ else - - @* *@ + + @item.OfferID + +
@($"{item.Inserted:yyyy-MM-dd}")
+
@($"{item.ValidUntil:yyyy-MM-dd}")
+ + + + @item.OfferCode
@item.Envir
diff --git a/Lux.UI/Components/Pages/Offers.razor.cs b/Lux.UI/Components/Pages/Offers.razor.cs index e97009eb..d3437d2a 100644 --- a/Lux.UI/Components/Pages/Offers.razor.cs +++ b/Lux.UI/Components/Pages/Offers.razor.cs @@ -2,7 +2,9 @@ using EgwCoreLib.Lux.Data.DbModel.Sales; using EgwCoreLib.Lux.Data.Services; using EgwCoreLib.Razor; using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; using NLog.LayoutRenderers; +using static EgwCoreLib.Lux.Core.Enums; namespace Lux.UI.Components.Pages { @@ -27,6 +29,23 @@ namespace Lux.UI.Components.Pages #region Protected Properties + /// + /// Filtro offerte: ogni stato / sole aperte + /// + protected bool AllStates + { + get => allState; + set + { + if (allState != value) + { + allState = value; + DoFilter(); + UpdateTable(); + } + } + } + protected string DivMainCss { get => SelRecord != null ? "col-6" : "col-12"; @@ -35,6 +54,14 @@ namespace Lux.UI.Components.Pages [Inject] protected DataLayerServices DLService { get; set; } = null!; + [Inject] + protected IJSRuntime JSRuntime { get; set; } = null!; + + protected string txtState + { + get => allState ? "Tutte" : "Aperte"; + } + #endregion Protected Properties #region Protected Methods @@ -59,6 +86,16 @@ namespace Lux.UI.Components.Pages }; } + 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; @@ -78,29 +115,62 @@ namespace Lux.UI.Components.Pages protected override async Task OnInitializedAsync() { + PeriodoSel = new EgwCoreLib.Utils.DtUtils.Periodo(EgwCoreLib.Utils.DtUtils.PeriodSet.ThisTrim); SetupArrows(); await ReloadData(); UpdateTable(); } + /// + /// Imposta lo stato dell'offerta VERIFICANDO i vari casi di stato di artenza/arrivo... + /// + /// + /// + /// + protected async Task SetState(OfferModel currRec, OfferStates newStatus) + { + // in primis: se è già confermata chiede una autorizzazione di conferma speciale + + // se va verso conferma ricorda che ora l'ordine passa in pianificazione + + /* --------------------------------- + * 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 del dizionario 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 + * --------------------------------- */ + + currRec.OffertState = newStatus; + await DLService.OffertUpsert(currRec); + await ReloadData(); + UpdateTable(); + } + #endregion Protected Methods #region Private Fields private List AllRecords = new List(); - + private bool allState = false; 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; @@ -145,6 +215,40 @@ namespace Lux.UI.Components.Pages 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 /// @@ -165,8 +269,22 @@ namespace Lux.UI.Components.Pages ///
private async Task ReloadData() { - AllRecords = await DLService.OfferGetAll(); - totalCount = AllRecords.Count(); + 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() @@ -184,7 +302,7 @@ namespace Lux.UI.Components.Pages private void UpdateTable() { // fix paginazione - ListRecords = AllRecords + ListRecords = ListFilt .Skip(numRecord * (currPage - 1)) .Take(numRecord) .ToList(); @@ -216,18 +334,5 @@ namespace Lux.UI.Components.Pages RefreshDisplay(); } #endif - /// - /// 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); - } } } \ No newline at end of file diff --git a/Lux.UI/Components/Pages/Orders.razor b/Lux.UI/Components/Pages/Orders.razor new file mode 100644 index 00000000..d767e1f6 --- /dev/null +++ b/Lux.UI/Components/Pages/Orders.razor @@ -0,0 +1,189 @@ +@page "/Orders" + +@if (EditRecord != null) +{ +
+
+
+
+
+ @EditRecord.OfferCode +
+
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+ +
+
+
+
+ +
+
+
+ +
+
+ + @if (currStep == CompileStep.Header) + { + + } + else if (currStep == CompileStep.General) + { + + } + else if (currStep == CompileStep.Rows) + { + + } + else if (currStep == CompileStep.Delivery) + { + + } + else if (currStep == CompileStep.FinalCheck) + { + + } +
+
+} +else +{ +
+
+
+
+ Ordini +
+
+ Periodo | ricerca testo +
+
+ +
+
+ @if (isLoading) + { + + } + else if (totalCount == 0) + { +
Nessun record trovato
+ } + else + { +
+
+ @* + + + + + + + + @if (SelRecord == null) + { + + } + + + + + + + + + @foreach (var item in ListRecords) + { + + + + + + + @if (SelRecord == null) + { + + } + + + + + + + } + +
+ + IDCodiceAgente/RivClienteDescrizione# righe# articoliImportoMarg.Esito
+ + + @item.OfferID + @item.OfferCode +
@item.Envir
+
+ @if (item.DealerNav != null) + { +
@item.DealerNav.FirstName @item.DealerNav.LastName
+
@item.DealerNav.VAT
+ } +
+ @if (item.CustomerNav != null) + { +
@item.CustomerNav.FirstName @item.CustomerNav.LastName
+
@item.CustomerNav.VAT
+ } +
@item.Description + @item.NumRows + + @item.NumItems + +
@item.TotalPrice.ToString("C2")
+
(@item.TotalCost.ToString("C2"))
+
+ @item.MaxDiscount.ToString("P2") + + + +
*@ +
Work In Progress
+
+ @if (SelRecord != null) + { +
+ +
+ } +
+ } +
+
+} diff --git a/Lux.UI/Components/Pages/Orders.razor.cs b/Lux.UI/Components/Pages/Orders.razor.cs new file mode 100644 index 00000000..bf04c45f --- /dev/null +++ b/Lux.UI/Components/Pages/Orders.razor.cs @@ -0,0 +1,207 @@ +using EgwCoreLib.Lux.Data.DbModel.Sales; +using EgwCoreLib.Lux.Data.Services; +using Microsoft.AspNetCore.Components; + +namespace Lux.UI.Components.Pages +{ + public partial class Orders + { + #region Protected Enums + + /// + /// Stato compilazione offerta + /// + protected enum CompileStep + { + Draft = 0, + Header = 1, + General, + Rows, + Delivery, + FinalCheck + } + + #endregion Protected Enums + + #region Protected Properties + + protected string DivMainCss + { + get => SelRecord != null ? "col-6" : "col-12"; + } + + [Inject] + protected DataLayerServices DLService { get; set; } = null!; + + #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 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() + { + SetupArrows(); + await ReloadData(); + UpdateTable(); + } + + #endregion Protected Methods + + #region Private Fields + + private List AllRecords = new List(); + + private int currPage = 1; + + private CompileStep currStep = CompileStep.Draft; + + private OfferModel? EditRecord = null; + + private bool isLoading = false; + + private List ListRecords = new List(); + + private int numRecord = 10; + + 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 DoClose() + { + EditRecord = null; + } + + /// + /// 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); + } + + /// + /// 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); + } + + /// + /// Legge i dati dei record completi + /// + private async Task ReloadData() + { + AllRecords = await DLService.OfferGetAll(); + totalCount = AllRecords.Count(); + } + + private void SetupArrows() + { + listBord01 = new(); + listBord01.Add(""); + listBord01.Add("White"); + listBord01.Add(""); + listBord01.Add(""); + } + + /// + /// Filtro e paginazione + /// + private void UpdateTable() + { + // fix paginazione + ListRecords = AllRecords + .Skip(numRecord * (currPage - 1)) + .Take(numRecord) + .ToList(); + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/Lux.UI/Lux.UI.csproj b/Lux.UI/Lux.UI.csproj index e17ff5a7..00007500 100644 --- a/Lux.UI/Lux.UI.csproj +++ b/Lux.UI/Lux.UI.csproj @@ -5,7 +5,7 @@ enable enable aspnet-Lux.UI-a758c101-a2f4-4e38-977d-1c4887dbbd50 - 0.9.2511.1312 + 0.9.2511.1416 diff --git a/Resources/ChangeLog.html b/Resources/ChangeLog.html index 304139ed..ff9714a7 100644 --- a/Resources/ChangeLog.html +++ b/Resources/ChangeLog.html @@ -1,6 +1,6 @@ LUX - Web Windows MES -

Versione: 0.9.2511.1312

+

Versione: 0.9.2511.1416


Note di rilascio:
  • diff --git a/Resources/VersNum.txt b/Resources/VersNum.txt index 0ed33c1f..525c8a4c 100644 --- a/Resources/VersNum.txt +++ b/Resources/VersNum.txt @@ -1 +1 @@ -0.9.2511.1312 +0.9.2511.1416 diff --git a/Resources/manifest.xml b/Resources/manifest.xml index 1f930d21..c72fa723 100644 --- a/Resources/manifest.xml +++ b/Resources/manifest.xml @@ -1,6 +1,6 @@ - 0.9.2511.1312 + 0.9.2511.1416 http://nexus.steamware.net/repository/SWS/GPW/stable/GPW.UI.zip http://nexus.steamware.net/repository/SWS/GPW/stable/ChangeLog.html false