Aggiunta cloning offerta!!!!!!!
This commit is contained in:
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Classe DTO x richieste di stima lavorazioni
|
||||
/// </summary>
|
||||
public class EstimReqPayloadDTO
|
||||
{
|
||||
/// <summary>
|
||||
/// UID Richiesta
|
||||
/// </summary>
|
||||
public string TaskUID { get; set; } = "";
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Batch di produzione di riferimento
|
||||
/// </summary>
|
||||
public int ProductionBatchID { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// ID Ordine di origine
|
||||
/// </summary>
|
||||
public int OrderID { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// ID univoco riga ordine
|
||||
/// </summary>
|
||||
public int OrderRowID { get; set; } = 0;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Filename (ove presente)
|
||||
/// </summary>
|
||||
public string FileName { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Valore serializzato dell'item della riga d'ordine
|
||||
/// </summary>
|
||||
public string SerializedData { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ItemTagList { get; set; } = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1494,6 +1494,65 @@ namespace EgwCoreLib.Lux.Data.Controllers
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upsert dell'elenco dei tags associati
|
||||
/// </summary>
|
||||
/// <param name="JobID">ID Job richiesto</param>
|
||||
/// <param name="reqTagList">Elenco Tags richiesto</param>
|
||||
/// <returns></returns>
|
||||
internal async Task<bool> JobTask2TagsUpsertAsync(int JobID, List<string> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eliminazione record richiesto
|
||||
/// </summary>
|
||||
@@ -1669,13 +1728,13 @@ namespace EgwCoreLib.Lux.Data.Controllers
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upsert dell'elenco dei tags associati
|
||||
/// esegue il cloning completo di un offerta e di TUTTE le relative righe di offerta...
|
||||
/// </summary>
|
||||
/// <param name="JobID">ID Job richiesto</param>
|
||||
/// <param name="reqTagList">Elenco Tags richiesto</param>
|
||||
/// <param name="rec2clone"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<bool> JobTask2TagsUpsertAsync(int JobID, List<string> reqTagList)
|
||||
internal async Task<bool> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco offerte da DB filtrate x periodo e stato
|
||||
/// </summary>
|
||||
/// <param name="inizio"></param>
|
||||
/// <param name="fine"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<List<OfferModel>> OfferGetFilt(DateTime inizio, DateTime fine)
|
||||
{
|
||||
List<OfferModel> dbResult = new List<OfferModel>();
|
||||
//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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco righe offerta specificata
|
||||
/// </summary>
|
||||
@@ -1811,6 +1937,46 @@ namespace EgwCoreLib.Lux.Data.Controllers
|
||||
return dbResult;
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Verifica e update offerte scadute
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
||||
internal async Task<bool> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elimina riga e sposta eventuali righe successive...
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace EgwCoreLib.Lux.Data.DbModel.Production
|
||||
public class ProductionBatchModel
|
||||
{
|
||||
/// <summary>
|
||||
/// ID dell'articolo
|
||||
/// ID del Batch di produzione
|
||||
/// </summary>
|
||||
[Key]
|
||||
public int ProductionBatchID { get; set; }
|
||||
|
||||
@@ -335,10 +335,10 @@ namespace EgwCoreLib.Lux.Data
|
||||
|
||||
// inizializzazione dei valori di default x Offer
|
||||
modelBuilder.Entity<OfferModel>().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 }
|
||||
|
||||
@@ -827,6 +827,20 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue Upsert info Tag associati
|
||||
/// </summary>
|
||||
/// <param name="JobID"></param>
|
||||
/// <param name="reqTagList"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> JobTask2TagsUpsertAsync(int JobID, List<string> reqTagList)
|
||||
{
|
||||
bool result = await dbController.JobTask2TagsUpsertAsync(JobID, reqTagList);
|
||||
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:JobTaskList:*");
|
||||
await ExecFlushRedisPatternAsync((RedisValue)$"{redisBaseKey}:JobStep:*");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue eliminazione + refresh cache
|
||||
/// </summary>
|
||||
@@ -903,17 +917,22 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue Upsert info Tag associati
|
||||
/// Esegue clone completo dell'offerta indicata e svuota la cache
|
||||
/// </summary>
|
||||
/// <param name="JobID"></param>
|
||||
/// <param name="reqTagList"></param>
|
||||
/// <param name="rec2clone"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> JobTask2TagsUpsertAsync(int JobID, List<string> reqTagList)
|
||||
public async Task<bool> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -951,6 +970,42 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco offerte da DB filtrate x periodo e stato
|
||||
/// </summary>
|
||||
/// <param name="inizio"></param>
|
||||
/// <param name="fine"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<OfferModel>> OfferGetFilt(DateTime inizio, DateTime fine)
|
||||
{
|
||||
string source = "DB";
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
List<OfferModel>? result = new List<OfferModel>();
|
||||
// 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<List<OfferModel>>($"{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<OfferModel>();
|
||||
}
|
||||
sw.Stop();
|
||||
Log.Debug($"OfferGetFilt | {source} | {sw.Elapsed.TotalMilliseconds}ms");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco righe offerta specificata
|
||||
/// </summary>
|
||||
@@ -1007,6 +1062,23 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Verifica offerte scadute, con update sul DB
|
||||
/// </summary>
|
||||
public async Task<bool> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converte il campo raw della BOM in lista oggetti da gestire
|
||||
/// </summary>
|
||||
|
||||
@@ -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<string>("ServerConf:ChannelPub") ?? "";
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Chiamata GET: test status alive
|
||||
/// GET: api/Prod/alive
|
||||
/// </summary>
|
||||
/// <param name="id">id oggetto</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("alive")]
|
||||
public async Task<IActionResult> Alive()
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
await Task.Delay(1);
|
||||
sw.Stop();
|
||||
Log.Info($"Alive | {sw.Elapsed.TotalMilliseconds:N3} ms");
|
||||
return Ok("OK");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chiamata GET:
|
||||
/// - elenco delle richieste di stima da eseguire
|
||||
/// - vengono registrate come "passate" al calcolo alla data-ora della richiesta
|
||||
/// GET: api/Prod/estimation
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("estimation")]
|
||||
public async Task<ActionResult<List<EstimReqPayloadDTO>>> EstimationRequestQueue()
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var listReq = new List<EstimReqPayloadDTO>();
|
||||
// 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<ItemTag, OrderRowUid>
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>0.9.2511.1312</Version>
|
||||
<Version>0.9.2511.1416</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -54,6 +54,11 @@
|
||||
<span class="fa-solid fa-cart-shopping px-2 fs-4" aria-hidden="true"></span> <span class="@hideText">Offerte</span>
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="Orders">
|
||||
<span class="fa-solid fa-cart-flatbed px-2 fs-4" aria-hidden="true"></span> <span class="@hideText">Ordini</span>
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="GenList">
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
@page "/Offers"
|
||||
|
||||
|
||||
|
||||
@if (EditRecord != null)
|
||||
{
|
||||
<div class="card shadow">
|
||||
@@ -49,7 +47,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
@@ -78,6 +75,30 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
if (EditStateRec != null)
|
||||
{
|
||||
<div class="modal" tabindex="-1" style="display:block; background-color: rgba(10,10,10,.6);" role="dialog">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header text-bg-info bg-gradient bg-opacity-50">
|
||||
<div class="modal-title fs-3">Imposta Stato Offerta</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @onclick="() => EditState(null)">
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
@foreach (var itemState in Enum.GetValues(typeof(Enums.OfferStates)).Cast<Enums.OfferStates>())
|
||||
{
|
||||
<div class="col">
|
||||
<button class="btn btn-sm btn-primary w-100 m-1" @onclick="() => SetState(EditStateRec, itemState)">@itemState</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="card shadow">
|
||||
<div class="card-header">
|
||||
<div class=" d-flex justify-content-between">
|
||||
@@ -85,7 +106,24 @@ else
|
||||
<b>Offerte</b> <button class="btn btn-success" @onclick="DoAdd"><i class="fa-solid fa-cart-plus"></i> Nuova</button>
|
||||
</div>
|
||||
<div class="px-0">
|
||||
Periodo | ricerca testo
|
||||
<div class="d-flex">
|
||||
<div class="px-1">
|
||||
<PeriodoSel E_PeriodoSel="SetPeriodo" CurrPeriodo="PeriodoSel"></PeriodoSel>
|
||||
</div>
|
||||
<div class="px-1">
|
||||
<div class="input-group input-group-sm mt-1">
|
||||
@* <span class="input-group-text">Stato</span> *@
|
||||
<div class="form-control ">
|
||||
<div class="form-check form-switch align-content-center">
|
||||
<input class="form-check-input" type="checkbox" @bind="@AllStates">
|
||||
<label class="form-check-label">@txtState</label>
|
||||
</div>
|
||||
</div>
|
||||
<input type="text" class="form-control" placeholder="ctrl-/" accesskey="/">
|
||||
<button class="btn btn-outline-secondary" type="button"><i class="fa-solid fa-rotate-right"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -110,6 +148,8 @@ else
|
||||
<button class="btn btn-sm btn-primary" title="Reset selezione" @onclick="DoReset"><i class="fa-solid fa-arrow-rotate-right"></i></button>
|
||||
</th>
|
||||
<th>ID</th>
|
||||
<th>Date</th>
|
||||
<th>Stato</th>
|
||||
<th>Codice</th>
|
||||
<th>Agente/Riv</th>
|
||||
<th>Cliente</th>
|
||||
@@ -129,10 +169,17 @@ else
|
||||
<tr class="@CheckSelect(item)">
|
||||
<td>
|
||||
<button class="btn btn-sm btn-primary" @onclick="() => DoSelect(item)"><i class="fa-solid fa-magnifying-glass"></i></button>
|
||||
<button class="btn btn-sm btn-info" @onclick="() => DoEdit(item)"><i class="fa-solid fa-pencil"></i></button>
|
||||
@* <button class="btn btn-sm btn-info" @onclick="() => DoEdit(item)"><i class="fa-solid fa-wand-magic"></i></button> *@
|
||||
<button class="btn btn-sm btn-primary" @onclick="() => DoEdit(item)"><i class="fa-solid fa-pencil"></i></button>
|
||||
<button class="btn btn-sm btn-info" @onclick="() => DoClone(item)"><i class="fa-solid fa-wand-magic"></i></button>
|
||||
</td>
|
||||
<td>@item.OfferID</td>
|
||||
<td>
|
||||
<div class="small" title="Inserita"><i class="fa-solid fa-circle"></i> @($"{item.Inserted:yyyy-MM-dd}")</div>
|
||||
<div class="small text-secondary" title="Scadenza"><i class="fa-solid fa-hourglass-half"></i> @($"{item.ValidUntil:yyyy-MM-dd}")</div>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-dark" @onclick="() => EditState(item)">@item.OffertState</button>
|
||||
</td>
|
||||
<td>
|
||||
@item.OfferCode
|
||||
<div class="small text-secondary">@item.Envir</div>
|
||||
|
||||
@@ -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
|
||||
|
||||
/// <summary>
|
||||
/// Filtro offerte: ogni stato / sole aperte
|
||||
/// </summary>
|
||||
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<bool>("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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposta lo stato dell'offerta VERIFICANDO i vari casi di stato di artenza/arrivo...
|
||||
/// </summary>
|
||||
/// <param name="currRec"></param>
|
||||
/// <param name="newStatus"></param>
|
||||
/// <returns></returns>
|
||||
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<OfferModel> AllRecords = new List<OfferModel>();
|
||||
|
||||
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<OfferModel> ListFilt = new List<OfferModel>();
|
||||
private List<OfferModel> ListRecords = new List<OfferModel>();
|
||||
|
||||
private int numRecord = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Periodo selezionato attuale
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Salva record ed avanza compilazione
|
||||
/// </summary>
|
||||
/// <param name="updRec"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rilegge tabella
|
||||
/// </summary>
|
||||
@@ -165,8 +269,22 @@ namespace Lux.UI.Components.Pages
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposta periodo da filtro
|
||||
/// </summary>
|
||||
/// <param name="newPeriod"></param>
|
||||
/// <returns></returns>
|
||||
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
|
||||
/// <summary>
|
||||
/// Salva record ed avanza compilazione
|
||||
/// </summary>
|
||||
/// <param name="updRec"></param>
|
||||
/// <returns></returns>
|
||||
private async Task DoSave(OfferModel updRec)
|
||||
{
|
||||
// salvo record
|
||||
await DLService.OffertUpsert(updRec);
|
||||
// cambio step
|
||||
CompileStep nextStep = currStep < CompileStep.FinalCheck ? currStep + 1 : currStep;
|
||||
AdvStep(nextStep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
@page "/Orders"
|
||||
|
||||
@if (EditRecord != null)
|
||||
{
|
||||
<div class="card shadow">
|
||||
<div class="card-header">
|
||||
<div class="card-title mb-0">
|
||||
<div class="d-flex justify-content-between align-items-center fs-4">
|
||||
<div class="px-0 fs-3">
|
||||
<b>@EditRecord.OfferCode</b>
|
||||
</div>
|
||||
<div class="px-4">
|
||||
<div class="d-flex">
|
||||
<div class="px-0 row">
|
||||
<div class="col px-0">
|
||||
<span @onclick="() => AdvStep(CompileStep.Header)">
|
||||
<StepArrow ObjId="1" StepText="Testata" BlockStyle="@(ArrowBackCol(CompileStep.Header))" StrokeWidth="4" ObjW="360" ObjH="60" StrokeColors="@listBord01" TipAngle="90" TextStyle="@txtStyle"></StepArrow>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col px-0">
|
||||
<span @onclick="() => AdvStep(CompileStep.General)">
|
||||
<StepArrow ObjId="2" StepText="Generale" BlockStyle="@(ArrowBackCol(CompileStep.General))" StrokeWidth="4" ObjW="360" ObjH="60" StrokeColors="@listBord01" TipAngle="90" TextStyle="@txtStyle"></StepArrow>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col px-0">
|
||||
<span @onclick="() => AdvStep(CompileStep.Rows)">
|
||||
<StepArrow ObjId="3" StepText="Righe" BlockStyle="@(ArrowBackCol(CompileStep.Rows))" StrokeWidth="4" ObjW="360" ObjH="60" StrokeColors="@listBord01" TipAngle="90" TextStyle="@txtStyle"></StepArrow>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col px-0">
|
||||
<span @onclick="() => AdvStep(CompileStep.Delivery)">
|
||||
<StepArrow ObjId="4" StepText="Consegna" BlockStyle="@(ArrowBackCol(CompileStep.Delivery))" StrokeWidth="4" ObjW="360" ObjH="60" StrokeColors="@listBord01" TipAngle="90" TextStyle="@txtStyle"></StepArrow>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col px-0">
|
||||
<span @onclick="() => AdvStep(CompileStep.FinalCheck)">
|
||||
<StepArrow ObjId="5" StepText="Controlli" BlockStyle="@(ArrowBackCol(CompileStep.FinalCheck))" StrokeWidth="4" ObjW="360" ObjH="60" StrokeColors="@listBord01" TipAngle="90" TextStyle="@txtStyle"></StepArrow>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-0">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="card" aria-label="Close" @onclick="DoReset">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
@if (currStep == CompileStep.Header)
|
||||
{
|
||||
<OfferMan CurrRecord="EditRecord" EC_Close="DoClose" EC_Updated="DoSave"></OfferMan>
|
||||
}
|
||||
else if (currStep == CompileStep.General)
|
||||
{
|
||||
<OfferCommonPar CurrRecord="EditRecord" EC_Close="DoClose" EC_Updated="DoSave"></OfferCommonPar>
|
||||
}
|
||||
else if (currStep == CompileStep.Rows)
|
||||
{
|
||||
<OfferRowMan CurrRecord="EditRecord" DisplayMode="EgwCoreLib.Lux.Core.Enums.DisplayMode.Edit"></OfferRowMan>
|
||||
}
|
||||
else if (currStep == CompileStep.Delivery)
|
||||
{
|
||||
<OfferDelivery CurrRecord="EditRecord" EC_Close="DoClose" EC_Updated="DoSave"></OfferDelivery>
|
||||
}
|
||||
else if (currStep == CompileStep.FinalCheck)
|
||||
{
|
||||
<OfferCheck CurrRecord="EditRecord" EC_Close="DoClose"></OfferCheck>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="card shadow">
|
||||
<div class="card-header">
|
||||
<div class=" d-flex justify-content-between">
|
||||
<div class="px-0 fs-3">
|
||||
<b>Ordini</b> <button class="btn btn-success" disabled @onclick="DoAdd"><i class="fa-solid fa-cart-plus"></i> Nuovo</button>
|
||||
</div>
|
||||
<div class="px-0">
|
||||
Periodo | ricerca testo
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (isLoading)
|
||||
{
|
||||
<LoadingData></LoadingData>
|
||||
}
|
||||
else if (totalCount == 0)
|
||||
{
|
||||
<div class="alert alert-info text-center display-4">Nessun record trovato</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row">
|
||||
<div class="@DivMainCss">
|
||||
@* <table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<button class="btn btn-sm btn-primary" title="Reset selezione" @onclick="DoReset"><i class="fa-solid fa-arrow-rotate-right"></i></button>
|
||||
</th>
|
||||
<th>ID</th>
|
||||
<th>Codice</th>
|
||||
<th>Agente/Riv</th>
|
||||
<th>Cliente</th>
|
||||
@if (SelRecord == null)
|
||||
{
|
||||
<th>Descrizione</th>
|
||||
}
|
||||
<th class="text-end"># righe</th>
|
||||
<th class="text-end"># articoli</th>
|
||||
<th class="text-end">Importo</th>
|
||||
<th class="text-end">Marg.</th>
|
||||
<th class="text-end">Esito</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in ListRecords)
|
||||
{
|
||||
<tr class="@CheckSelect(item)">
|
||||
<td>
|
||||
<button class="btn btn-sm btn-primary" @onclick="() => DoSelect(item)"><i class="fa-solid fa-magnifying-glass"></i></button>
|
||||
<button class="btn btn-sm btn-info" @onclick="() => DoEdit(item)"><i class="fa-solid fa-pencil"></i></button>
|
||||
</td>
|
||||
<td>@item.OfferID</td>
|
||||
<td>
|
||||
@item.OfferCode
|
||||
<div class="small text-secondary">@item.Envir</div>
|
||||
</td>
|
||||
<td>
|
||||
@if (item.DealerNav != null)
|
||||
{
|
||||
<div class=""><b>@item.DealerNav.FirstName</b> @item.DealerNav.LastName</div>
|
||||
<div class="small">@item.DealerNav.VAT</div>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (item.CustomerNav != null)
|
||||
{
|
||||
<div class=""><b>@item.CustomerNav.FirstName</b> @item.CustomerNav.LastName</div>
|
||||
<div class="small">@item.CustomerNav.VAT</div>
|
||||
}
|
||||
</td>
|
||||
@if (SelRecord == null)
|
||||
{
|
||||
<td>@item.Description</td>
|
||||
}
|
||||
<td class="text-end">
|
||||
@item.NumRows
|
||||
</td>
|
||||
<td class="text-end">
|
||||
@item.NumItems
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="fw-bold" title="Prezzo Finito">@item.TotalPrice.ToString("C2")</div>
|
||||
<div class="small text-secondary" title="RockBottom Price">(@item.TotalCost.ToString("C2"))</div>
|
||||
</td>
|
||||
<td class="text-end" title="Margine / Sconto MAX applicabile">
|
||||
@item.MaxDiscount.ToString("P2")
|
||||
</td>
|
||||
<td class="text-end" title="Esito">
|
||||
<button class="btn btn-sm btn-success"><i class="fa-solid fa-thumbs-up"></i></button>
|
||||
<button class="btn btn-sm btn-danger"><i class="fa-solid fa-thumbs-down"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table> *@
|
||||
<div class="alert alert-info fs-3">Work In Progress</div>
|
||||
</div>
|
||||
@if (SelRecord != null)
|
||||
{
|
||||
<div class="col-6">
|
||||
<OfferRowMan CurrRecord="@SelRecord" DisplayMode="EgwCoreLib.Lux.Core.Enums.DisplayMode.Preview" EC_Updated="() => ForceReload()"></OfferRowMan>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -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
|
||||
|
||||
/// <summary>
|
||||
/// Stato compilazione offerta
|
||||
/// </summary>
|
||||
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<OfferModel> AllRecords = new List<OfferModel>();
|
||||
|
||||
private int currPage = 1;
|
||||
|
||||
private CompileStep currStep = CompileStep.Draft;
|
||||
|
||||
private OfferModel? EditRecord = null;
|
||||
|
||||
private bool isLoading = false;
|
||||
|
||||
private List<OfferModel> ListRecords = new List<OfferModel>();
|
||||
|
||||
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<string> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Salva record ed avanza compilazione
|
||||
/// </summary>
|
||||
/// <param name="updRec"></param>
|
||||
/// <returns></returns>
|
||||
private async Task DoSave(OfferModel updRec)
|
||||
{
|
||||
// salvo record
|
||||
await DLService.OffertUpsert(updRec);
|
||||
// cambio step
|
||||
CompileStep nextStep = currStep < CompileStep.FinalCheck ? currStep + 1 : currStep;
|
||||
AdvStep(nextStep);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rilegge tabella
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Legge i dati dei record completi
|
||||
/// </summary>
|
||||
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("");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filtro e paginazione
|
||||
/// </summary>
|
||||
private void UpdateTable()
|
||||
{
|
||||
// fix paginazione
|
||||
ListRecords = AllRecords
|
||||
.Skip(numRecord * (currPage - 1))
|
||||
.Take(numRecord)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>aspnet-Lux.UI-a758c101-a2f4-4e38-977d-1c4887dbbd50</UserSecretsId>
|
||||
<Version>0.9.2511.1312</Version>
|
||||
<Version>0.9.2511.1416</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>LUX - Web Windows MES</i>
|
||||
<h4>Versione: 0.9.2511.1312</h4>
|
||||
<h4>Versione: 0.9.2511.1416</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.9.2511.1312
|
||||
0.9.2511.1416
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>0.9.2511.1312</version>
|
||||
<version>0.9.2511.1416</version>
|
||||
<url>http://nexus.steamware.net/repository/SWS/GPW/stable/GPW.UI.zip</url>
|
||||
<changelog>http://nexus.steamware.net/repository/SWS/GPW/stable/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
Reference in New Issue
Block a user