Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d24b2ada0c | |||
| 0a9ccffe28 | |||
| 207d305327 | |||
| caa4b4f590 | |||
| e45cb0595e | |||
| 77e7e39985 | |||
| b2e9ae76d4 | |||
| 460eb769dc | |||
| 5e38749c65 | |||
| 91083b6c4a | |||
| de562b1287 | |||
| 470c9a2191 | |||
| 26e36e7124 | |||
| bef0ee6000 | |||
| 9e4822d529 | |||
| 7f9685a007 |
@@ -6,7 +6,6 @@ using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MP.Data.Controllers
|
||||
@@ -99,6 +98,25 @@ namespace MP.Data.Controllers
|
||||
return ListValuesFilt("AnagArticoli", "Tipo");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco codice articoli che abbiano dati Dossier
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<string> ArticleWithDossier()
|
||||
{
|
||||
List<string> dbResult = new List<string>();
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
dbResult = dbCtx
|
||||
.DbSetDossiers
|
||||
.AsNoTracking()
|
||||
.Select(i => i.OdlNav.CodArticolo)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eliminazione Record
|
||||
/// </summary>
|
||||
@@ -192,26 +210,6 @@ namespace MP.Data.Controllers
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Statistiche ODL calcolate (da stored stp_STAT_ODL)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<StatODLModel>> StatOdl(int IdxOdl)
|
||||
{
|
||||
List<StatODLModel> dbResult = new List<StatODLModel>();
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
var IdxODL = new SqlParameter("@IdxODL", IdxOdl);
|
||||
|
||||
dbResult = await dbCtx
|
||||
.DbSetStatOdl
|
||||
.FromSqlRaw("EXEC stp_STAT_ODL @IdxODL", IdxODL)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update Record
|
||||
/// </summary>
|
||||
@@ -421,7 +419,7 @@ namespace MP.Data.Controllers
|
||||
.FirstOrDefault();
|
||||
if (currRec != null)
|
||||
{
|
||||
currRec.Valore= editRec.Valore;
|
||||
currRec.Valore = editRec.Valore;
|
||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||
}
|
||||
else
|
||||
@@ -440,6 +438,7 @@ namespace MP.Data.Controllers
|
||||
}
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco valori link (x home e navMenu laterale)
|
||||
/// </summary>
|
||||
@@ -449,6 +448,32 @@ namespace MP.Data.Controllers
|
||||
return ListLinkFilt("SpecLink");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggiunta record EventList
|
||||
/// </summary>
|
||||
/// <param name="newRec"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> EvListInsert(EventListModel newRec)
|
||||
{
|
||||
bool fatto = false;
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
try
|
||||
{
|
||||
var currRec = dbCtx
|
||||
.DbSetEvList
|
||||
.Add(newRec);
|
||||
await dbCtx.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Log.Error($"Eccezione durante EvListInsert{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
await Task.Delay(1);
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco ultimi n record flux log dato macchina e flusso (ordinato x data registrazione)
|
||||
/// </summary>
|
||||
@@ -497,14 +522,14 @@ namespace MP.Data.Controllers
|
||||
/// <param name="startDate">Data inizio</param>
|
||||
/// <param name="endDate">Data fine</param>
|
||||
/// <returns></returns>
|
||||
public List<ODLModel> ListODLFilt(bool inCorso, string codArt, string keyRichPart, DateTime startDate, DateTime endDate)
|
||||
public List<ODLModel> ListODLFilt(bool inCorso, string codArt, string keyRichPart, string IdxMacchina, DateTime startDate, DateTime endDate)
|
||||
{
|
||||
List<ODLModel> dbResult = new List<ODLModel>();
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
dbResult = dbCtx
|
||||
.DbSetODL
|
||||
.Where(x => ((inCorso && x.DataFine == null) || ((!inCorso && x.DataFine != null) && x.DataInizio >= startDate && x.DataInizio <= endDate)) && (x.KeyRichiesta.Contains(keyRichPart) || keyRichPart == "*") && (codArt == "*" || x.CodArticolo.Contains(codArt)))
|
||||
.Where(x => ((inCorso && x.DataFine == null) || ((!inCorso && x.DataFine != null) && x.DataInizio >= startDate && x.DataInizio <= endDate)) && (x.KeyRichiesta.Contains(keyRichPart) || keyRichPart == "*") && (x.IdxMacchina.Contains(IdxMacchina) || IdxMacchina == "*") && (codArt == "*" || x.CodArticolo.Contains(codArt)))
|
||||
.AsNoTracking()
|
||||
.Include(m => m.MachineNav)
|
||||
.Include(a => a.ArticoloNav)
|
||||
@@ -595,25 +620,6 @@ namespace MP.Data.Controllers
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco codice articoli che abbiano dati Dossier
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<string> ArticleWithDossier()
|
||||
{
|
||||
List<string> dbResult = new List<string>();
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
dbResult = dbCtx
|
||||
.DbSetDossiers
|
||||
.AsNoTracking()
|
||||
.Select(i => i.OdlNav.CodArticolo)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco da tabella MappaStatoExpl
|
||||
/// </summary>
|
||||
@@ -634,6 +640,148 @@ namespace MP.Data.Controllers
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chiusura ODL con eventuale conferma pezzi
|
||||
/// </summary>
|
||||
/// <param name="idxOdl">idx odl da chiudere</param>
|
||||
/// <param name="idxMacchina">idx macchina</param>
|
||||
/// <param name="matrOpr">matricola operatore</param>
|
||||
/// <param name="confPezzi">indica se confermare i pezzi prima di chiudere ODL</param>
|
||||
/// <param name="confRett">Conferma con rettifica (ev 121) x pezzi lasciati in macchina</param>
|
||||
/// <param name="modoConfProd">Modo conferma produzione (0=periodo, 1=giorno, 2=turno)</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> ODLClose(int idxOdl, string idxMacchina, int matrOpr, bool confPezzi, bool confRett, int modoConfProd)
|
||||
{
|
||||
bool fatto = false;
|
||||
if (idxOdl > 0)
|
||||
{
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
// preparo i parametri
|
||||
var IdxODL = new SqlParameter("@IdxODL", idxOdl);
|
||||
var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacchina);
|
||||
|
||||
// FARE FIXME TODO !!! da valutare casi setup/autoconferma...
|
||||
#if false
|
||||
// controllo se HO pezzi da confermare...
|
||||
var statoProd = StatoProdMacchina(idxMacchina);
|
||||
if (statoProd.pezziNonConfermati < 1)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
// se richiesto confermo produzione
|
||||
if (confPezzi)
|
||||
{
|
||||
var MatrApp = new SqlParameter("@MatrApp", idxMacchina);
|
||||
|
||||
/* ----------------------------------
|
||||
* CONFERMA PEZZI
|
||||
*
|
||||
* condizioni da verificare:
|
||||
* - gestione rettifica (ev121) / pezzi da LASCIARE in macchina
|
||||
* - conferma a zero pezzi (setup) oppure con i pezzi fatti e non ancora confermati
|
||||
*
|
||||
*
|
||||
*
|
||||
* */
|
||||
|
||||
// recupero i dati dei pezzi da confermare... con DbSetPzProd + exec
|
||||
// stp_PzProd_getByMacchina 'SIMUL_01'
|
||||
|
||||
// stp_ConfermaProduzCompletaFull
|
||||
/*
|
||||
* @idxMacchina NVARCHAR(50),
|
||||
@MatrApp INT,
|
||||
@dataFrom DATETIME,
|
||||
@dataTo DATETIME,
|
||||
@pezziConf INT,
|
||||
@pezziLasciati INT, -- pezzi lasciati = evento 121 (-) pre conferma e (+) dopo --> da lasciare in macchina post conferma
|
||||
@pezziScar INT = 0, -- pezzi scartati (registrati da 2016.11.20) DA INDICARE COME VALORE > 0!!! sennò faccio ABS...
|
||||
@TipoConf INT = 0, -- Tipo intervallo conferma: 0 = periodo intero, 1 = per giorni, 2 = per turni
|
||||
@DataOraApp DATETIME = NULL, -- di norma GETDATE() nel programma - serve per ricalcolo
|
||||
@TestConferma BIT = 1 -- TestConferma : 1 = verifica conf. duplicata e inserisci in ElencoConfermeProd, 0 = nessuna verifica e inserimento ( per ricalcolo )
|
||||
*/
|
||||
}
|
||||
|
||||
// ora chiudo ODL
|
||||
try
|
||||
{
|
||||
var dbResult = await dbCtx
|
||||
.DbSetStatOdl
|
||||
.FromSqlRaw("EXEC stp_ODL_fineProd @IdxODL, @IdxMacchina", IdxODL, IdxMacchina)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Log.Error($"Eccezione durante ODLClose{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
}
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero odl data chiave
|
||||
/// </summary>
|
||||
/// <param name="idxOdl"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public ODLModel OdlGetByKey(int idxOdl)
|
||||
{
|
||||
ODLModel dbResult = new ODLModel();
|
||||
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
dbResult = dbCtx
|
||||
.DbSetODL
|
||||
.FirstOrDefault(x => x.IdxOdl == idxOdl);
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero Odl CORRENTE x macchina (SE c'è)
|
||||
/// </summary>
|
||||
/// <param name="idxMacchina"></param>
|
||||
/// <returns></returns>
|
||||
public ODLModel OdlGetCurrentByMacc(string idxMacchina)
|
||||
{
|
||||
ODLModel dbResult = new ODLModel();
|
||||
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
dbResult = dbCtx
|
||||
.DbSetODL
|
||||
.FirstOrDefault(x => x.IdxMacchina == idxMacchina && x.DataInizio != null && x.DataFine == null);
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Statistiche ODL calcolate (da stored stp_STAT_ODL)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<StatODLModel>> OdlStart(int IdxOdl)
|
||||
{
|
||||
List<StatODLModel> dbResult = new List<StatODLModel>();
|
||||
if (IdxOdl > 0)
|
||||
{
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
var IdxODL = new SqlParameter("@IdxODL", IdxOdl);
|
||||
|
||||
dbResult = await dbCtx
|
||||
.DbSetStatOdl
|
||||
.FromSqlRaw("EXEC stp_STAT_ODL @IdxODL", IdxODL)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco parametri validi x una data macchina
|
||||
/// </summary>
|
||||
@@ -655,6 +803,80 @@ namespace MP.Data.Controllers
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero PODL da chiave
|
||||
/// </summary>
|
||||
/// <param name="idxPODL"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<PODLModel> PODL_getByKey(int idxPODL)
|
||||
{
|
||||
PODLModel dbResult = new PODLModel();
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
try
|
||||
{
|
||||
dbResult = dbCtx
|
||||
.DbSetPODL
|
||||
.AsNoTracking()
|
||||
.Where(x => x.IdxPromessa == idxPODL)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Log.Error($"Eccezione durante PODL_getByKey{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
await Task.Delay(1);
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Avvio setup ODL da PODL
|
||||
/// </summary>
|
||||
/// <param name="editRec"></param>
|
||||
/// <param name="matrOpr"></param>
|
||||
/// <param name="tcRich"></param>
|
||||
/// <param name="pzPallet"></param>
|
||||
/// <param name="note"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> PODL_startSetup(PODLModel editRec, int matrOpr, double tcRich, int pzPallet, string note)
|
||||
{
|
||||
bool answ = false;
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
try
|
||||
{
|
||||
var currRec = dbCtx
|
||||
.DbSetPODL
|
||||
.AsNoTracking()
|
||||
.Where(x => x.IdxPromessa == editRec.IdxPromessa)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (currRec != null)
|
||||
{
|
||||
// eseguo stored attrezzaggio
|
||||
var IdxPromessa = new SqlParameter("@idxPromessa", editRec.IdxPromessa);
|
||||
var MatrOpr = new SqlParameter("@MatrOpr", matrOpr);
|
||||
var IdxMacchina = new SqlParameter("@IdxMacchina", editRec.IdxMacchina);
|
||||
var TCRichAttr = new SqlParameter("@TCRichAttr", tcRich);
|
||||
var PzPallet = new SqlParameter("@PzPallet", pzPallet);
|
||||
var Note = new SqlParameter("@Note", note);
|
||||
var callResult = await dbCtx
|
||||
.Database
|
||||
.ExecuteSqlRawAsync("EXEC stp_ODL_inizioSetupPromessa @idxPromessa, @MatrOpr, @IdxMacchina, @TCRichAttr, @PzPallet, @Note", IdxPromessa, MatrOpr, IdxMacchina, TCRichAttr, PzPallet, Note);
|
||||
|
||||
answ = true;
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Log.Error($"Eccezione durante PODL_doSetup{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
await Task.Delay(1);
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eliminazione Record
|
||||
/// </summary>
|
||||
@@ -755,6 +977,26 @@ namespace MP.Data.Controllers
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stato prod macchina
|
||||
/// </summary>
|
||||
/// <param name="idxMacchina"></param>
|
||||
/// <returns></returns>
|
||||
public StatoProdModel StatoProdMacchina(string idxMacchina)
|
||||
{
|
||||
StatoProdModel dbResult = new StatoProdModel();
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
var IdxMacchina = new SqlParameter("@IdxMacchina", idxMacchina);
|
||||
dbResult = dbCtx
|
||||
.DbSetStatoProd
|
||||
.FromSqlRaw("EXEC stp_PzProd_getByMacchina @IdxMacchina", IdxMacchina)
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault();
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
|
||||
#nullable disable
|
||||
// <Auto-Generated>
|
||||
// This is here so CodeMaid doesn't reorganize this document
|
||||
// </Auto-Generated>
|
||||
namespace MP.Data.DatabaseModels
|
||||
{
|
||||
[Table("EventList")]
|
||||
public partial class EventListModel
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
[MaxLength(50)]
|
||||
public string IdxMacchina { get; set; } = "NA";
|
||||
public DateTime? InizioStato { get; set; } = DateTime.Now;
|
||||
public int IdxTipo { get; set; } = 0;
|
||||
|
||||
[MaxLength(50)]
|
||||
public string CodArticolo { get; set; } = "";
|
||||
|
||||
[MaxLength(250)]
|
||||
public string Value { get; set; } = "";
|
||||
|
||||
public int MatrOpr { get; set; } = 0;
|
||||
|
||||
[MaxLength(20)]
|
||||
public string pallet { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Navigazione oggetto Machine
|
||||
/// </summary>
|
||||
[ForeignKey("IdxMacchina")]
|
||||
public virtual Macchine MachineNav { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// Navigazione oggetto Articolo
|
||||
/// </summary>
|
||||
[ForeignKey("CodArticolo")]
|
||||
public virtual AnagArticoli ArticoloNav { get; set; } = null!;
|
||||
|
||||
#endregion Public Properties
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
#nullable disable
|
||||
// <Auto-Generated>
|
||||
// This is here so CodeMaid doesn't reorganize this document
|
||||
// </Auto-Generated>
|
||||
namespace MP.Data.DatabaseModels
|
||||
{
|
||||
public partial class StatoProdModel
|
||||
{
|
||||
[Key]
|
||||
public string idxMacchina { get; set; } = "NA";
|
||||
public int pezziNonConfermati { get; set; } = 0;
|
||||
public DateTime DataFrom { get; set; } = DateTime.Now;
|
||||
public DateTime DataTo { get; set; } = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,8 @@ namespace MP.Data
|
||||
public virtual DbSet<FluxLog> DbSetFluxLog { get; set; }
|
||||
public virtual DbSet<Dossiers> DbSetDossiers { get; set; }
|
||||
public virtual DbSet<StatODLModel> DbSetStatOdl { get; set; }
|
||||
public virtual DbSet<StatoProdModel> DbSetStatoProd { get; set; }
|
||||
public virtual DbSet<EventListModel> DbSetEvList { get; set; }
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
@@ -299,6 +301,12 @@ namespace MP.Data
|
||||
|
||||
});
|
||||
|
||||
modelBuilder.Entity<EventListModel>(entity =>
|
||||
{
|
||||
entity.HasKey(e => new { e.IdxMacchina, e.InizioStato, e.IdxTipo});
|
||||
|
||||
});
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,26 @@ else if (totalCount == 0)
|
||||
else
|
||||
{
|
||||
<div class="row">
|
||||
@if (currRecord != null && !showStats && isCurrOdl)
|
||||
{
|
||||
<div class="col-6 col-lg-8">
|
||||
</div>
|
||||
<div class="col-6 col-lg-4 text-end">
|
||||
@*<div class="px-2 input-group" title="Selezionare Data-Ora chiusura ODL">
|
||||
<label class="input-group-text" for="dtMax"><i class="fa-regular fa-calendar-minus"></i></label>
|
||||
<input class="form-control" @bind="@selDtFine" id="dtMax" type="datetime-local">
|
||||
<button @onclick="() => chiudiOdl()" class="btn btn-danger btn-sm btn-">Registra chiusura ODL <i class="far fa-stop-circle"></i></button>
|
||||
</div>*@
|
||||
<button @onclick="() => chiudiOdl()" class="btn btn-danger btn-sm btn-">Registra chiusura ODL <i class="far fa-stop-circle"></i></button>
|
||||
</div>
|
||||
}
|
||||
<div class="col-12">
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<button @onclick="() => resetSel()" class="btn btn-primary btn-sm"><i class="bi bi-arrow-counterclockwise"></i></button>
|
||||
</th>
|
||||
<th><i class="fa-solid fa-file"></i> Articolo</th>
|
||||
<th><i class="fa-solid fa-screwdriver-wrench"></i> Fase</th>
|
||||
<th><i class="fa-solid fa-hard-drive"></i> Macchina</th>
|
||||
@@ -28,6 +44,17 @@ else
|
||||
@foreach (var record in ListRecords)
|
||||
{
|
||||
<tr class="@checkSelect(@record.IdxOdl)">
|
||||
|
||||
<td>
|
||||
@if (isCurrOdl)
|
||||
{
|
||||
<button class="btn btn-primary btn-sm" @onclick="() => selRecord(record)"><i class="fa-solid fa-magnifying-glass"></i></button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="btn btn-secondary btn-sm disabled"><i class="fa-solid fa-magnifying-glass"></i></button>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@record.CodArticolo
|
||||
<div class="small textConsensed text-secondary">@record.ArticoloNav.DescArticolo</div>
|
||||
@@ -83,7 +110,7 @@ else
|
||||
<b>@record.DurataMinuti</b>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn btn-sm btn-primary py-0" type="button" @onclick="() => selectRecord(record)" data-bs-toggle="modal" data-bs-target="#staticBackdrop" title="Mostra statistiche"><i class="fa-solid fa-chart-pie"></i></button>
|
||||
<button class="btn btn-sm btn-primary py-0" type="button" @onclick="() => selectRecord(record)" data-bs-toggle="modal" data-bs-target="#myModal" title="Mostra statistiche"><i class="fa-solid fa-chart-pie"></i></button>
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
</td>
|
||||
@@ -91,7 +118,7 @@ else
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="modal fade" id="staticBackdrop" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
||||
<div class="modal fade" id="myModal" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-xl">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary col-12">
|
||||
@@ -110,11 +137,11 @@ else
|
||||
</div>
|
||||
}
|
||||
<div class="col-1 text-end">
|
||||
<button type="button" class="btn btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
<button type="button" class="btn btn-close" data-bs-dismiss="modal" aria-label="Close" @onclick="TriggerDotNetInstanceMethod"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body col-12">
|
||||
@if (currRecord != null)
|
||||
@if (currRecord != null && showStats)
|
||||
{
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="col-8">
|
||||
@@ -197,7 +224,7 @@ else
|
||||
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" style="width: @Math.Round(calcolaPerc(statRecord.TotDurata),0)%; background-color:@statRecord.Css;" aria-valuemax="100">@($"{calcolaPerc(statRecord.TotDurata):N1}%")</div>
|
||||
<div class="progress-bar @colorChanger(@statRecord.Css)" role="progressbar" aria-valuenow="0" aria-valuemin="0" style="width: @Math.Round(calcolaPerc(statRecord.TotDurata),0)%; background-color:@statRecord.Css;" aria-valuemax="100">@($"{calcolaPerc(statRecord.TotDurata):N1}%")</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -207,13 +234,15 @@ else
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 dcContainer">
|
||||
@if (currRecord != null)
|
||||
@if (currRecord != null && ListOdlStats != null)
|
||||
{
|
||||
<div class="dcBox">
|
||||
<ODLPlot SelectedOdl="@currRecord.IdxOdl"></ODLPlot>
|
||||
</div>
|
||||
<div class="dcBox dcOverlay">
|
||||
<b class="fs-3">@currRecord.DurataMinuti</b>
|
||||
<div class="dcBox dcOverlay d-flex">
|
||||
<div class="align-self-center text-center w-100">
|
||||
<b class="fs-3">@currRecord.DurataMinuti</b>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -227,5 +256,3 @@ else
|
||||
</div>
|
||||
}
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
||||
@@ -3,6 +3,8 @@ using Microsoft.JSInterop;
|
||||
using MP.Data;
|
||||
using MP.Data.DatabaseModels;
|
||||
using MP.SPEC.Data;
|
||||
using MP.SPEC.Pages;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace MP.SPEC.Components
|
||||
{
|
||||
@@ -40,9 +42,31 @@ namespace MP.SPEC.Components
|
||||
|
||||
public string formDurata(double durataMin)
|
||||
{
|
||||
return Utils.FormDurata(durataMin);
|
||||
return MP.Data.Utils.FormDurata(durataMin);
|
||||
}
|
||||
|
||||
//oggetto contenente le funzioni del code behind che sono jsInvokable
|
||||
private DotNetObjectReference<ListODL>? objRef;
|
||||
|
||||
#if true //FUNZIONA SE IL METODO TriggerDotNetInstanceMethod() E' IN ONCLOCK BOTTONE
|
||||
|
||||
[JSInvokable]
|
||||
public void svuotaRecord()
|
||||
{
|
||||
currRecord = null;
|
||||
|
||||
}
|
||||
[JSInvokable]
|
||||
public void setHelper()
|
||||
{
|
||||
objRef = DotNetObjectReference.Create(this);
|
||||
}
|
||||
public async Task TriggerDotNetInstanceMethod()
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("recordDeselect", objRef);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Properties
|
||||
@@ -60,9 +84,30 @@ namespace MP.SPEC.Components
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Registra chiusura ODL alla data indicata
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected async Task chiudiOdl()
|
||||
{
|
||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Sei sicuro di voler chiudere l'ODL corrente?"))
|
||||
return;
|
||||
|
||||
if (currRecord != null)
|
||||
{
|
||||
// effettua chiusura sul DB
|
||||
await MDService.ODLClose(currRecord.IdxOdl, currRecord.IdxMacchina, 0, true);
|
||||
// ricarica...
|
||||
await selectRecord(null);
|
||||
}
|
||||
await reloadData();
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
ListStati = await MDService.AnagStatiComm();
|
||||
objRef = DotNetObjectReference.Create(this);
|
||||
//await JSRuntime.InvokeVoidAsync("setHelper", objRef);
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
@@ -70,31 +115,66 @@ namespace MP.SPEC.Components
|
||||
await reloadData();
|
||||
}
|
||||
|
||||
protected string colorChanger(string colorCSS)
|
||||
{
|
||||
string answ = "";
|
||||
if (colorCSS == "yellow")
|
||||
{
|
||||
answ = "text-dark";
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
//protected double durataMin(DateTime? DataInizio, DateTime? DataFine)
|
||||
//{
|
||||
// DateTime end = DataInizio != null ? (DateTime)DataFine : DateTime.Now;
|
||||
// var tsDurata = (end).Subtract((DateTime)DataInizio);
|
||||
|
||||
// return tsDurata.TotalMinutes;
|
||||
//}
|
||||
|
||||
protected async void OnSeachUpdated()
|
||||
{
|
||||
await InvokeAsync(() =>
|
||||
{
|
||||
PagerResetReq.InvokeAsync(true);
|
||||
//currPage = 1;
|
||||
Task task = UpdateData();
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
|
||||
protected async Task resetSel()
|
||||
{
|
||||
await selectRecord(null);
|
||||
await reloadData();
|
||||
}
|
||||
|
||||
protected async Task selectRecord(ODLModel? currRec)
|
||||
{
|
||||
showStats = true;
|
||||
await Task.Delay(1);
|
||||
currRecord = currRec;
|
||||
if (currRec != null)
|
||||
{
|
||||
showStats = true;
|
||||
ListOdlStats = await MDService.StatOdl(currRec.IdxOdl);
|
||||
}
|
||||
else
|
||||
{
|
||||
showStats = false;
|
||||
ListOdlStats = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task selRecord(ODLModel? currRec)
|
||||
{
|
||||
await Task.Delay(1);
|
||||
selDtFine = DateTime.Now;
|
||||
currRecord = currRec;
|
||||
showStats = false;
|
||||
ListOdlStats = null;
|
||||
}
|
||||
|
||||
protected async Task UpdateData()
|
||||
{
|
||||
await selectRecord(null);
|
||||
@@ -106,11 +186,13 @@ namespace MP.SPEC.Components
|
||||
#region Private Fields
|
||||
|
||||
private ODLModel? currRecord = null;
|
||||
|
||||
private List<StatODLModel>? ListOdlStats;
|
||||
private List<double>? ListOdlStatsData = new List<double>();
|
||||
private List<string>? ListOdlStatsLabels = new List<string>();
|
||||
|
||||
private List<ODLModel>? ListRecords;
|
||||
|
||||
private List<ListValues>? ListStati;
|
||||
|
||||
private List<ODLModel>? SearchRecords;
|
||||
|
||||
#endregion Private Fields
|
||||
@@ -123,6 +205,14 @@ namespace MP.SPEC.Components
|
||||
set => MessageService.currPage = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indica se si tratti di ODL correnti
|
||||
/// </summary>
|
||||
private bool isCurrOdl
|
||||
{
|
||||
get => currFilter.IsActive;
|
||||
}
|
||||
|
||||
private bool isLoading { get; set; } = false;
|
||||
|
||||
private int numRecord
|
||||
@@ -131,6 +221,12 @@ namespace MP.SPEC.Components
|
||||
set => MessageService.numRecord = value;
|
||||
}
|
||||
|
||||
private DateTime selDtFine { get; set; } = DateTime.Now;
|
||||
private bool showStats { get; set; } = false;
|
||||
#if false
|
||||
private List<double>? ListOdlStatsData = new List<double>();
|
||||
private List<string>? ListOdlStatsLabels = new List<string>();
|
||||
#endif
|
||||
private int totalCount { get; set; } = 0;
|
||||
|
||||
#endregion Private Properties
|
||||
@@ -170,7 +266,7 @@ namespace MP.SPEC.Components
|
||||
private async Task reloadData()
|
||||
{
|
||||
isLoading = true;
|
||||
SearchRecords = await MDService.ListODLFilt(currFilter.IsActive, currFilter.SearchVal, currFilter.CodStato, currFilter.DtStart, currFilter.DtEnd);
|
||||
SearchRecords = await MDService.ListODLFilt(currFilter.IsActive, currFilter.SearchVal, currFilter.CodStato, currFilter.IdxMacchina, currFilter.DtStart, currFilter.DtEnd);
|
||||
totalCount = SearchRecords.Count;
|
||||
ListRecords = SearchRecords.Skip(numRecord * (currPage - 1)).Take(numRecord).ToList();
|
||||
await Task.Delay(1);
|
||||
|
||||
@@ -35,6 +35,17 @@ else
|
||||
<td class="text-nowrap">
|
||||
<button @onclick="() => selRecord(record)" class="btn btn-primary btn-sm" title="Modifica Record"><i class="bi bi-pencil-square"></i></button>
|
||||
<button @onclick="() => cloneRecord(record)" class="btn btn-info btn-sm" title="Duplica Record"><i class="bi bi-clipboard-check"></i></button>
|
||||
@if (canStartOdl(record.IdxMacchina))
|
||||
{
|
||||
<button @onclick="() => startOdl(record)" class="btn btn-success btn-sm" title="Avvia PODL">
|
||||
<i class="far fa-play-circle"></i>
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="btn btn-secondary btn-sm disabled" title="ODL ancora in corso">
|
||||
<i class="far fa-play-circle"></i>
|
||||
</button>}
|
||||
</td>
|
||||
<td>
|
||||
@record.CodArticolo
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace MP.SPEC.Components
|
||||
protected MpDataService MDService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected IOApiService MpIoApiCall { get; set; }
|
||||
protected IOApiService MpIoApiCall { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected MessageService MsgService { get; set; } = null!;
|
||||
@@ -95,7 +95,7 @@ namespace MP.SPEC.Components
|
||||
return;
|
||||
await Task.Delay(1);
|
||||
var done = await MDService.PODLDeleteRecord(selRec);
|
||||
await callSyncDb(selRec);
|
||||
await callSyncDb(selRec.IdxMacchina);
|
||||
currRecord = null;
|
||||
await reloadData();
|
||||
await Task.Delay(1);
|
||||
@@ -142,6 +142,52 @@ namespace MP.SPEC.Components
|
||||
await RecordSel.InvokeAsync(selRec);
|
||||
}
|
||||
|
||||
protected async Task startOdl(PODLModel selRec)
|
||||
{
|
||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Sei sicuro di voler avviare PODL selezionato?"))
|
||||
return;
|
||||
|
||||
if (selRec != null)
|
||||
{
|
||||
int idxEvento = 0;
|
||||
string evMess = "";
|
||||
// verifico ancora NON ci sia ODL corrente/aperto
|
||||
if (canStartOdl(selRec.IdxMacchina))
|
||||
{
|
||||
await callStartSetup(selRec.IdxMacchina);
|
||||
await Task.Delay(1);
|
||||
// chiamo stored stp_ODL_inizioSetupPromessa e recupero ODL corrente
|
||||
bool fatto = await MDService.POdlDoSetup(selRec);
|
||||
if (fatto)
|
||||
{
|
||||
var currPOdl = await MDService.PODL_getByKey(selRec.IdxPromessa);
|
||||
var newOdl = await MDService.OdlGetByKey(currPOdl.IdxOdl);
|
||||
|
||||
// registro evento...
|
||||
idxEvento = 2;
|
||||
evMess = $"Inizio Setup | PODL {selRec.IdxPromessa}";
|
||||
processaEvento(selRec.IdxMacchina, idxEvento, evMess, newOdl.IdxOdl, newOdl.CodArticolo);
|
||||
|
||||
// aspetto 1 sec
|
||||
await Task.Delay(1000);
|
||||
|
||||
// registro inizio produzione
|
||||
idxEvento = 2;
|
||||
evMess = $"Registrata inizio Produzione | PODL {selRec.IdxPromessa} | ODL {newOdl.IdxOdl} | ART {newOdl.CodArticolo}";
|
||||
processaEvento(selRec.IdxMacchina, idxEvento, evMess, newOdl.IdxOdl, newOdl.CodArticolo);
|
||||
|
||||
// chiamo task x IOB
|
||||
await callForceUpdate(selRec.IdxMacchina);
|
||||
await Task.Delay(1);
|
||||
await callForceUpdate(selRec.IdxMacchina);
|
||||
await Task.Delay(1);
|
||||
await callSyncDb(selRec.IdxMacchina);
|
||||
await Task.Delay(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task UpdateData()
|
||||
{
|
||||
currRecord = null;
|
||||
@@ -200,12 +246,67 @@ namespace MP.SPEC.Components
|
||||
/// </summary>
|
||||
/// <param name="selRec"></param>
|
||||
/// <returns></returns>
|
||||
private async Task callSyncDb(PODLModel selRec)
|
||||
private async Task addTask2Exe(string idxMacc, string taskName, string taskVal)
|
||||
{
|
||||
// compongo URL e chiamo
|
||||
string restUrl = $"IOB/addTask2Exe/{idxMacc}?taskName={taskName}&taskVal={taskVal}";
|
||||
try
|
||||
{
|
||||
var response = await MpIoApiCall.callMpIoUrlGet(restUrl);
|
||||
}
|
||||
catch(Exception exc)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chiama metodo x chiedere force Update
|
||||
/// </summary>
|
||||
/// <param name="selRec"></param>
|
||||
/// <returns></returns>
|
||||
private async Task callForceUpdate(string IdxMacc)
|
||||
{
|
||||
// chiamo aggiunta task SyncDb...
|
||||
await addTask2Exe(IdxMacc, "ForceUpdate", $"SPEC|TS:{DateTime.Now:yyMMddHHmmss}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chiama metodo x indicare inizio setup
|
||||
/// </summary>
|
||||
/// <param name="selRec"></param>
|
||||
/// <returns></returns>
|
||||
private async Task callStartSetup(string IdxMacc)
|
||||
{
|
||||
// chiamo evento inizio setup
|
||||
await addTask2Exe(IdxMacc, "startSetup", $"SPEC|TS:{DateTime.Now:yyMMddHHmmss}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chiama metodo x chiedere sync DB
|
||||
/// </summary>
|
||||
/// <param name="IdxMacc"></param>
|
||||
/// <returns></returns>
|
||||
private async Task callSyncDb(string IdxMacc)
|
||||
{
|
||||
// chiamo aggiunta task SyncDb...
|
||||
await addTask2Exe(IdxMacc, "syncDbData", "");
|
||||
#if false
|
||||
string idxMacc = selRec.IdxMacchina;
|
||||
string restUrl = $"IOB/addTask2Exe/{idxMacc}?taskName=syncDbData&taskVal=";
|
||||
var response = await MpIoApiCall.callMpIoUrlGet(restUrl);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// verifica se sia avviabile ODL x macchina
|
||||
/// </summary>
|
||||
/// <param name="idxMacchina"></param>
|
||||
/// <returns></returns>
|
||||
private bool canStartOdl(string idxMacchina)
|
||||
{
|
||||
var currOdl = MDService.OdlGetCurrentByMacc(idxMacchina);
|
||||
bool answ = currOdl == null;
|
||||
return answ;
|
||||
}
|
||||
|
||||
private async void MessageService_EA_PageUpdated()
|
||||
@@ -224,6 +325,40 @@ namespace MP.SPEC.Components
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// processa evento richiesto
|
||||
/// </summary>
|
||||
/// <param name="idxMacc"></param>
|
||||
/// <param name="idxEvento"></param>
|
||||
/// <param name="userMsg"></param>
|
||||
/// <param name="idxODL"></param>
|
||||
private async void processaEvento(string idxMacc, int idxEvento, string userMsg, int idxODL, string codArticolo)
|
||||
{
|
||||
// se manca codart calcolo...
|
||||
if (string.IsNullOrEmpty(codArticolo))
|
||||
{
|
||||
var currOdl = await MDService.OdlGetByKey(idxODL);
|
||||
if (currOdl != null)
|
||||
{
|
||||
codArticolo = currOdl.CodArticolo;
|
||||
}
|
||||
}
|
||||
|
||||
// scrivo evento scriviRigaEventoBarcode
|
||||
EventListModel newRec = new EventListModel()
|
||||
{
|
||||
IdxMacchina = idxMacc,
|
||||
InizioStato = DateTime.Now,
|
||||
IdxTipo = idxEvento,
|
||||
CodArticolo = codArticolo,
|
||||
MatrOpr = 0,
|
||||
pallet = "",
|
||||
Value = userMsg
|
||||
};
|
||||
|
||||
await MDService.EvListInsert(newRec);
|
||||
}
|
||||
|
||||
private async Task reloadData()
|
||||
{
|
||||
isLoading = true;
|
||||
|
||||
+190
-107
@@ -127,6 +127,41 @@ namespace MP.SPEC.Data
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco Codice articolo con dati dossier gestiti
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<string>> ArticleWithDossier()
|
||||
{
|
||||
List<string>? result = new List<string>();
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string readType = "DB";
|
||||
string currKey = redisArtByDossier;
|
||||
// cerco in redis dato valore sel macchina...
|
||||
RedisValue rawData = redisDb.StringGet(currKey);
|
||||
if (rawData.HasValue)
|
||||
{
|
||||
result = JsonConvert.DeserializeObject<List<string>>($"{rawData}");
|
||||
readType = "REDIS";
|
||||
}
|
||||
else
|
||||
{
|
||||
result = await Task.FromResult(dbController.ArticleWithDossier());
|
||||
// serializzp e salvo...
|
||||
rawData = JsonConvert.SerializeObject(result);
|
||||
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
||||
}
|
||||
if (result == null)
|
||||
{
|
||||
result = new List<string>();
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"ArticleWithDossier | Read from {readType}: {ts.TotalMilliseconds}ms");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eliminazione record selezionato
|
||||
/// </summary>
|
||||
@@ -274,69 +309,6 @@ namespace MP.SPEC.Data
|
||||
return await Task.FromResult(dbController.ConfigUpdate(updRec));
|
||||
}
|
||||
|
||||
public List<FluxLogDTO> getFluxLog(string Valore)
|
||||
{
|
||||
List<FluxLogDTO> answ = new List<FluxLogDTO>();
|
||||
DossierFluxLogDTO? result = JsonConvert.DeserializeObject<DossierFluxLogDTO>(Valore);
|
||||
if (result != null)
|
||||
{
|
||||
if (result.ODL != null)
|
||||
{
|
||||
answ = result
|
||||
.ODL
|
||||
.OrderBy(x => x.CodFlux)
|
||||
.ToList();
|
||||
// inizializzo SE necessario
|
||||
foreach (var item in answ)
|
||||
{
|
||||
item.ValoreEdit = String.IsNullOrEmpty(item.ValoreEdit) ? item.Valore : item.ValoreEdit;
|
||||
}
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
public async Task<bool> updateDossierValue(Dossiers currDoss, FluxLogDTO editFL)
|
||||
{
|
||||
bool answ = false;
|
||||
// recupero intero set valori dossier deserializzando...
|
||||
var fluxLogList = getFluxLog(currDoss.Valore);
|
||||
await Task.Delay(1);
|
||||
|
||||
// se tutto ok
|
||||
if (fluxLogList != null)
|
||||
{
|
||||
// da provare...!!!!
|
||||
|
||||
// elimino vecchio record
|
||||
var currRec = fluxLogList.FirstOrDefault(x => x.CodFlux == editFL.CodFlux && x.dtEvento == editFL.dtEvento);
|
||||
if (currRec != null)
|
||||
{
|
||||
fluxLogList.Remove(currRec);
|
||||
// aggiungo nuovo
|
||||
fluxLogList.Add(editFL);
|
||||
}
|
||||
|
||||
|
||||
// serializzo nuovamente valore
|
||||
DossierFluxLogDTO? result = new DossierFluxLogDTO();
|
||||
var ODLflux = result.ODL.ToList();
|
||||
foreach (var item in fluxLogList)
|
||||
{
|
||||
ODLflux.Add(item);
|
||||
}
|
||||
|
||||
DossierFluxLogDTO updatedResult = new DossierFluxLogDTO(){ODL = ODLflux};
|
||||
|
||||
string rawVal = JsonConvert.SerializeObject(updatedResult);
|
||||
currDoss.Valore = rawVal;
|
||||
// aggiorno record sul DB
|
||||
await dbController.DossiersUpdateValore(currDoss);
|
||||
}
|
||||
|
||||
return answ;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Clear database controller
|
||||
@@ -454,16 +426,6 @@ namespace MP.SPEC.Data
|
||||
return Task.FromResult(dbController.AnagGruppiAziende());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Statistiche ODL calcolate (da stored stp_STAT_ODL)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task<List<StatODLModel>> StatOdl(int IdxOdl)
|
||||
{
|
||||
return dbController.StatOdl(IdxOdl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restitusice elenco fasi
|
||||
/// </summary>
|
||||
@@ -478,6 +440,16 @@ namespace MP.SPEC.Data
|
||||
return Task.FromResult(dbController.ElencoLink());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggiunta record EventList
|
||||
/// </summary>
|
||||
/// <param name="newRec"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> EvListInsert(EventListModel newRec)
|
||||
{
|
||||
return await dbController.EvListInsert(newRec);
|
||||
}
|
||||
|
||||
public async Task<bool> FlushRedisCache()
|
||||
{
|
||||
await Task.Delay(1);
|
||||
@@ -514,6 +486,28 @@ namespace MP.SPEC.Data
|
||||
return Task.FromResult(currTagConf);
|
||||
}
|
||||
|
||||
public List<FluxLogDTO> getFluxLog(string Valore)
|
||||
{
|
||||
List<FluxLogDTO> answ = new List<FluxLogDTO>();
|
||||
DossierFluxLogDTO? result = JsonConvert.DeserializeObject<DossierFluxLogDTO>(Valore);
|
||||
if (result != null)
|
||||
{
|
||||
if (result.ODL != null)
|
||||
{
|
||||
answ = result
|
||||
.ODL
|
||||
.OrderBy(x => x.CodFlux)
|
||||
.ToList();
|
||||
// inizializzo SE necessario
|
||||
foreach (var item in answ)
|
||||
{
|
||||
item.ValoreEdit = String.IsNullOrEmpty(item.ValoreEdit) ? item.Valore : item.ValoreEdit;
|
||||
}
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// restituisce il valore da REDIS associato al tag richeisto
|
||||
/// </summary>
|
||||
@@ -537,10 +531,11 @@ namespace MP.SPEC.Data
|
||||
/// <param name="inCorso">Stato ODL: true=in corso/completato</param>
|
||||
/// <param name="codArt">Cod articolo</param>
|
||||
/// <param name="keyRichPart">KeyRich (parziale) da cercare (es cod stato x yacht)</param>
|
||||
/// <param name="IdxMacchina">id macchina da cercare</param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<ODLModel>> ListODLFilt(bool inCorso, string codArt, string keyRichPart, DateTime startDate, DateTime endDate)
|
||||
public async Task<List<ODLModel>> ListODLFilt(bool inCorso, string codArt, string keyRichPart, string IdxMacchina, DateTime startDate, DateTime endDate)
|
||||
{
|
||||
return await Task.FromResult(dbController.ListODLFilt(inCorso, codArt, keyRichPart, startDate, endDate));
|
||||
return await Task.FromResult(dbController.ListODLFilt(inCorso, codArt, keyRichPart, IdxMacchina, startDate, endDate));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -624,40 +619,61 @@ namespace MP.SPEC.Data
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua chiusura dell'ODL indicato, andand
|
||||
/// </summary>
|
||||
/// <param name="idxOdl">idx odl da chiudere</param>
|
||||
/// <param name="idxMacchina">idx macchina</param>
|
||||
/// <param name="matrOpr">matricola operatore</param>
|
||||
/// <param name="confPezzi">indica se confermare i pezzi priam di chiudere ODL</param>
|
||||
public async Task<bool> ODLClose(int idxOdl, string idxMacchina, int matrOpr, bool confPezzi)
|
||||
{
|
||||
bool fatto = false;
|
||||
await Task.Delay(1);
|
||||
// recupero dati x conf modalità conferma
|
||||
var configData = await ConfigGetAll();
|
||||
if (configData != null)
|
||||
{
|
||||
bool confRett = false;
|
||||
var currRec = configData.FirstOrDefault(x => x.Chiave == "confRett");
|
||||
if (currRec != null)
|
||||
{
|
||||
bool.TryParse(currRec.Valore, out confRett);
|
||||
}
|
||||
int modoConfProd = 0;
|
||||
currRec = configData.FirstOrDefault(x => x.Chiave == "modoConfProd");
|
||||
if (currRec != null)
|
||||
{
|
||||
int.TryParse(currRec.Valore, out modoConfProd);
|
||||
}
|
||||
// chiamo metodo conferma!
|
||||
fatto = await dbController.ODLClose(idxOdl, idxMacchina, matrOpr, confPezzi, confRett, modoConfProd);
|
||||
}
|
||||
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco Codice articolo con dati dossier gestiti
|
||||
/// Record ODL da chaive
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<string>> ArticleWithDossier()
|
||||
public async Task<ODLModel> OdlGetByKey(int IdxOdl)
|
||||
{
|
||||
List<string>? result = new List<string>();
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string readType = "DB";
|
||||
string currKey = redisArtByDossier;
|
||||
// cerco in redis dato valore sel macchina...
|
||||
RedisValue rawData = redisDb.StringGet(currKey);
|
||||
if (rawData.HasValue)
|
||||
{
|
||||
result = JsonConvert.DeserializeObject<List<string>>($"{rawData}");
|
||||
readType = "REDIS";
|
||||
}
|
||||
else
|
||||
{
|
||||
result = await Task.FromResult(dbController.ArticleWithDossier());
|
||||
// serializzp e salvo...
|
||||
rawData = JsonConvert.SerializeObject(result);
|
||||
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
|
||||
}
|
||||
if (result == null)
|
||||
{
|
||||
result = new List<string>();
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"ArticleWithDossier | Read from {readType}: {ts.TotalMilliseconds}ms");
|
||||
return result;
|
||||
await Task.Delay(1);
|
||||
var dbResult = dbController.OdlGetByKey(IdxOdl);
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ODL corrente x macchina
|
||||
/// </summary>
|
||||
/// <param name="idxMacchina"></param>
|
||||
/// <returns></returns>
|
||||
public ODLModel OdlGetCurrentByMacc(string idxMacchina)
|
||||
{
|
||||
// cache REDIS...
|
||||
var dbResult = dbController.OdlGetCurrentByMacc(idxMacchina);
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -696,6 +712,16 @@ namespace MP.SPEC.Data
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero PODL da chiave
|
||||
/// </summary>
|
||||
/// <param name="idxPODL"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<PODLModel> PODL_getByKey(int idxPODL)
|
||||
{
|
||||
return await dbController.PODL_getByKey(idxPODL);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eliminazione record selezionato
|
||||
/// </summary>
|
||||
@@ -706,6 +732,16 @@ namespace MP.SPEC.Data
|
||||
return await dbController.PODLDeleteRecord(currRec);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Avvio fase setup per il record selezionato
|
||||
/// </summary>
|
||||
/// <param name="currRec"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> POdlDoSetup(PODLModel currRec)
|
||||
{
|
||||
return await dbController.PODL_startSetup(currRec, 0, 1, 1, "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggiornamento record selezionato
|
||||
/// </summary>
|
||||
@@ -716,6 +752,55 @@ namespace MP.SPEC.Data
|
||||
return await dbController.PODLUpdateRecord(currRec);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Statistiche ODL calcolate (da stored stp_STAT_ODL)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task<List<StatODLModel>> StatOdl(int IdxOdl)
|
||||
{
|
||||
return dbController.OdlStart(IdxOdl);
|
||||
}
|
||||
|
||||
public async Task<bool> updateDossierValue(Dossiers currDoss, FluxLogDTO editFL)
|
||||
{
|
||||
bool answ = false;
|
||||
// recupero intero set valori dossier deserializzando...
|
||||
var fluxLogList = getFluxLog(currDoss.Valore);
|
||||
await Task.Delay(1);
|
||||
|
||||
// se tutto ok
|
||||
if (fluxLogList != null)
|
||||
{
|
||||
// da provare...!!!!
|
||||
|
||||
// elimino vecchio record
|
||||
var currRec = fluxLogList.FirstOrDefault(x => x.CodFlux == editFL.CodFlux && x.dtEvento == editFL.dtEvento);
|
||||
if (currRec != null)
|
||||
{
|
||||
fluxLogList.Remove(currRec);
|
||||
// aggiungo nuovo
|
||||
fluxLogList.Add(editFL);
|
||||
}
|
||||
|
||||
// serializzo nuovamente valore
|
||||
DossierFluxLogDTO? result = new DossierFluxLogDTO();
|
||||
var ODLflux = result.ODL.ToList();
|
||||
foreach (var item in fluxLogList)
|
||||
{
|
||||
ODLflux.Add(item);
|
||||
}
|
||||
|
||||
DossierFluxLogDTO updatedResult = new DossierFluxLogDTO() { ODL = ODLflux };
|
||||
|
||||
string rawVal = JsonConvert.SerializeObject(updatedResult);
|
||||
currDoss.Valore = rawVal;
|
||||
// aggiorno record sul DB
|
||||
await dbController.DossiersUpdateValore(currDoss);
|
||||
}
|
||||
|
||||
return answ;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
@@ -741,6 +826,7 @@ namespace MP.SPEC.Data
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private const string redisArtByDossier = redisBaseAddr + "SPEC:Cache:ArtByDossier";
|
||||
private const string redisBaseAddr = "MP:";
|
||||
|
||||
private const string redisConfKey = redisBaseAddr + "SPEC:Cache:Config";
|
||||
@@ -750,9 +836,6 @@ namespace MP.SPEC.Data
|
||||
private const string redisFluxByMac = redisBaseAddr + "SPEC:Cache:FluxByMac";
|
||||
|
||||
private const string redisMacByFlux = redisBaseAddr + "SPEC:Cache:MacByFlux";
|
||||
|
||||
private const string redisArtByDossier = redisBaseAddr + "SPEC:Cache:ArtByDossier";
|
||||
|
||||
private const string redisMacList = redisBaseAddr + "SPEC:Cache:MacList";
|
||||
|
||||
private const string redisStatoCom = redisBaseAddr + "SPEC:Cache:StatoCom";
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace MP.SPEC.Data
|
||||
#region Public Properties
|
||||
|
||||
public string CodStato { get; set; } = "*";
|
||||
public string IdxMacchina { get; set; } = "*";
|
||||
public int CurrPage { get; set; } = 1;
|
||||
public int NumRec { get; set; } = 10;
|
||||
public DateTime DtEnd { get; set; } = Utils.InitDatetime(DateTime.Now, 5);
|
||||
@@ -37,6 +38,9 @@ namespace MP.SPEC.Data
|
||||
if (CodStato != item.CodStato)
|
||||
return false;
|
||||
|
||||
if (IdxMacchina != item.IdxMacchina)
|
||||
return false;
|
||||
|
||||
if (MaxRecord != item.MaxRecord)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>MP.SPEC</RootNamespace>
|
||||
<Version>6.16.2210.1417</Version>
|
||||
<Version>6.16.2210.1809</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+22
-4
@@ -37,11 +37,11 @@
|
||||
<div>
|
||||
|
||||
<div class="small mt-2">
|
||||
<label class="px-2" for="macchina" title="Selezionare inizio periodo">Macchina</label>
|
||||
<label class="px-2" for="fase" title="Selezionare inizio periodo">Fase</label>
|
||||
</div>
|
||||
<div class="input-group px-2">
|
||||
<label class="input-group-text" for="macchina" title="Selezionare la fase da visualizzare"><i class="fa-solid fa-screwdriver-wrench"></i></label>
|
||||
<select @bind="@selStato" id="macchina" class="form-select" title="Selezionare la fase da visualizzare">
|
||||
<label class="input-group-text" for="fase" title="Selezionare la fase da visualizzare"><i class="fa-solid fa-screwdriver-wrench"></i></label>
|
||||
<select @bind="@selStato" id="fase" class="form-select" title="Selezionare la fase da visualizzare">
|
||||
<option value="*">--- Tutti ---</option>
|
||||
@if (ListStati != null)
|
||||
{
|
||||
@@ -53,6 +53,25 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<div class="small mt-2">
|
||||
<label class="px-2" for="macchina" title="Selezionare inizio periodo">Macchina</label>
|
||||
</div>
|
||||
<div class="input-group px-2">
|
||||
<label class="input-group-text" for="macchina" title="Selezionare la macchina da visualizzare"><i class="fa-solid fa-hard-drive"></i></label>
|
||||
<select @bind="@selMacchina" id="macchina" class="form-select" title="Selezionare la macchina da visualizzare">
|
||||
<option value="*">--- Tutti ---</option>
|
||||
@if (ListMacchine != null)
|
||||
{
|
||||
foreach (var item in ListMacchine)
|
||||
{
|
||||
<option value="@item">@item</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@if (!isActive)
|
||||
{
|
||||
<div class="small mt-2">
|
||||
@@ -83,4 +102,3 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ namespace MP.SPEC.Pages
|
||||
// resetto search
|
||||
MsgService.SearchVal = "";
|
||||
ListStati = await MDService.AnagStatiComm();
|
||||
ListMacchine = await MDService.MacchineWithFlux();
|
||||
#if false
|
||||
// carico dati
|
||||
await reloadData();
|
||||
@@ -123,6 +124,7 @@ namespace MP.SPEC.Pages
|
||||
#region Private Fields
|
||||
|
||||
private List<MP.Data.DatabaseModels.ListValues>? ListStati;
|
||||
private List<string>? ListMacchine;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
@@ -159,6 +161,11 @@ namespace MP.SPEC.Pages
|
||||
get => currFilter.CodStato;
|
||||
set => currFilter.CodStato = value;
|
||||
}
|
||||
private string selMacchina
|
||||
{
|
||||
get => currFilter.IdxMacchina;
|
||||
set => currFilter.IdxMacchina = value;
|
||||
}
|
||||
|
||||
private int totalCount
|
||||
{
|
||||
|
||||
@@ -20,19 +20,19 @@ namespace MP.SPEC.Pages
|
||||
#region Protected Properties
|
||||
|
||||
[Inject]
|
||||
protected IJSRuntime JSRuntime { get; set; }
|
||||
protected IJSRuntime JSRuntime { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected MpDataService MDService { get; set; }
|
||||
protected MpDataService MDService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected IOApiService MpIoApiCall { get; set; }
|
||||
protected IOApiService MpIoApiCall { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected MessageService MsgService { get; set; }
|
||||
protected MessageService MsgService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected NavigationManager NavManager { get; set; }
|
||||
protected NavigationManager NavManager { get; set; } = null!;
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
|
||||
<script src="lib/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="_framework/blazor.server.js" autostart="false"></script>
|
||||
<script src="lib/chartjs-adapter-luxon/chartjs-adapter-luxon.js"></script>
|
||||
<script src="lib/chartBoot.js"></script>
|
||||
<script src="lib/modalHandler.js"></script>
|
||||
<script src="lib/Chart.js/chart.js"></script>
|
||||
|
||||
@*Gestione autoriconnessione: https://github.com/dotnet/aspnetcore/issues/38305 (vedere anche https://docs.microsoft.com/it-it/aspnet/core/blazor/fundamentals/signalr?view=aspnetcore-6.0#modify-the-reconnection-handler-blazor-server)*@
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo MAPOSPEC </i>
|
||||
<h4>Versione: 6.16.2210.1417</h4>
|
||||
<h4>Versione: 6.16.2210.1809</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
6.16.2210.1417
|
||||
6.16.2210.1809
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>6.16.2210.1417</version>
|
||||
<version>6.16.2210.1809</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-SPEC/stable/LAST/MP.SPEC.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-SPEC/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -95,7 +95,6 @@ a,
|
||||
}
|
||||
.dcOverlay {
|
||||
z-index: 9;
|
||||
margin: 8.5rem;
|
||||
}
|
||||
#blazor-error-ui {
|
||||
background: lightyellow;
|
||||
|
||||
@@ -102,7 +102,6 @@ a, .btn-link {
|
||||
|
||||
.dcOverlay {
|
||||
z-index: 9;
|
||||
margin: 8.5rem;
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,20 +1,12 @@
|
||||
///Setup del chart desiderato con id univoco
|
||||
window.setup = (id, config) => {
|
||||
var ctx = document.getElementById(id).getContext('2d');
|
||||
//let currentDate = new Date();
|
||||
//console.log(currentDate + " - Calling setup...");
|
||||
console.log(id);
|
||||
if (window['myChart'] instanceof Chart) {
|
||||
//window.myChart.destroy();
|
||||
window['myChart'].destroy();
|
||||
console.log("Chart " + id + " destroyed!");
|
||||
window['myChart'] = new Chart(ctx, config);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
window['myChart'] = new Chart(ctx, config);
|
||||
//console.log("Chart " + id + " created!");
|
||||
console.log(window['myChart']);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//window.recordDeselect = (dotNetHelper) => {
|
||||
// var myModalEl = document.getElementById('myModal')
|
||||
// myModalEl.addEventListener('hidden.bs.modal', function (event) {
|
||||
// // do something...
|
||||
// //dotNetHelper.invokeMethodAsync('TriggerDotNetInstanceMethod');
|
||||
// return dotNetHelper.invokeMethodAsync('svuotaRecord');
|
||||
// console.log("fatto");
|
||||
// });
|
||||
//};
|
||||
|
||||
|
||||
//TENTATIVO POPOLAMENTO HELPER PER POTER INVOCARE IL METODO DOPO
|
||||
//let helper;
|
||||
|
||||
//window.setHelper = (dotNetHelper) => {
|
||||
// helper = dotNetHelper.invokeMethodAsync('setHelper');
|
||||
// console.log(helper);
|
||||
// return dotNetHelper.invokeMethodAsync('setHelper');
|
||||
//}
|
||||
|
||||
//BECCA QUANDO LA MODALE VIENE CHIUSA ED ESEGUE
|
||||
document.addEventListener('click', function (e) {
|
||||
if (e.target.id === 'myModal') {
|
||||
console.log('chiuso');
|
||||
|
||||
return helper.invokeMethodAsync('svuotaRecord');
|
||||
console.log("fatto");
|
||||
} else {
|
||||
console.log('aperto');
|
||||
}
|
||||
e.stopPropagation();
|
||||
}, false);
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>MP.Stats</RootNamespace>
|
||||
<UserSecretsId>826e877c-ba70-4253-84cb-d0b1cafd4440</UserSecretsId>
|
||||
<Version>6.16.2210.0716</Version>
|
||||
<Version>6.16.2210.1708</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo statistiche MAPO</i>
|
||||
<h4>Versione: 6.16.2210.0716</h4>
|
||||
<h4>Versione: 6.16.2210.1708</h4>
|
||||
<br />
|
||||
Note di rilascio:
|
||||
<ul>
|
||||
|
||||
@@ -1 +1 @@
|
||||
6.16.2210.0716
|
||||
6.16.2210.1708
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>6.16.2210.0716</version>
|
||||
<version>6.16.2210.1708</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-STATS/stable/LAST/MP.Stats.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-STATS/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
Reference in New Issue
Block a user