commit lavorazioni

This commit is contained in:
2026-02-03 14:34:40 +01:00
parent 301537cc9f
commit 752eb3e077
10 changed files with 344 additions and 13 deletions

View File

@ -0,0 +1,9 @@
using OAService.Service.Repository;
using OAService.Service.Servizi.Interfacce;
using TecniStamp.Domain;
namespace TecniStamp.Service.Interfaces;
public interface ILavorazioneService : ITService<Lavorazione>
{
}

View File

@ -9,4 +9,5 @@ public interface IManagerService
ISezioneService SezioneService { get; set; } ISezioneService SezioneService { get; set; }
IUserService UtenteService { get; set; } IUserService UtenteService { get; set; }
IMacchinarioService MacchinarioService { get; set; } IMacchinarioService MacchinarioService { get; set; }
ILavorazioneService LavorazioneService { get; set; }
} }

View File

@ -0,0 +1,13 @@
using OAService.Service.Servizi.Implementazioni;
using TecniStamp.Domain;
using TecniStamp.Service.Interfaces;
using TecniStamp.Service.Repository;
namespace TecniStamp.Service;
public class LavorazioneService : TService<Lavorazione>, ILavorazioneService
{
public LavorazioneService(ITecniStampUnitOfWork unitOfWork) : base(unitOfWork)
{
}
}

View File

@ -5,7 +5,7 @@ namespace TecniStamp.Service;
public class ManagerService : IManagerService public class ManagerService : IManagerService
{ {
public ManagerService(IUserService userService, ISezioneService sezioneService, IPermissionService permissionService, IRuoloService ruoloService, public ManagerService(IUserService userService, ISezioneService sezioneService, IPermissionService permissionService, IRuoloService ruoloService,
IFeatureService featureService, IMacchinarioService macchinarioService, ICommessaService commessaService) IFeatureService featureService, IMacchinarioService macchinarioService, ICommessaService commessaService, ILavorazioneService lavorazioneService)
{ {
UtenteService = userService; UtenteService = userService;
SezioneService = sezioneService; SezioneService = sezioneService;
@ -14,6 +14,7 @@ public class ManagerService : IManagerService
FeatureService = featureService; FeatureService = featureService;
MacchinarioService = macchinarioService; MacchinarioService = macchinarioService;
CommessaService = commessaService; CommessaService = commessaService;
LavorazioneService = lavorazioneService;
} }
public ICommessaService CommessaService { get; set; } public ICommessaService CommessaService { get; set; }
@ -23,4 +24,5 @@ public class ManagerService : IManagerService
public ISezioneService SezioneService { get; set; } public ISezioneService SezioneService { get; set; }
public IUserService UtenteService { get; set; } public IUserService UtenteService { get; set; }
public IMacchinarioService MacchinarioService { get; set; } public IMacchinarioService MacchinarioService { get; set; }
public ILavorazioneService LavorazioneService { get; set; }
} }

View File

@ -37,4 +37,7 @@ Global
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A54D2BE1-E74F-43DA-B84A-8B16EC6B4098}
EndGlobalSection
EndGlobal EndGlobal

View File

@ -1,7 +1,97 @@
@page "/anagrafiche/lavorazioni" @page "/anagrafiche/lavorazioni"
@using Microsoft.EntityFrameworkCore
@using TecniStamp.Model
@using TecniStamp.Model.Common
@using TecniStamp.Utils
@rendermode InteractiveServer
@inject AuthenticationStateProvider auth
<PageTitle>Lavorazioni</PageTitle> <PageTitle>Lavorazioni</PageTitle>
<Breadcrumb Items="BreadcrumbList" />
<main role="main">
<div class="container-fluid h-100 mt-5">
<div class="row justify-content-start">
<div class="row row-cards">
<div class="col-auto ms-auto">
<div class="btn-list">
<a href="/Anagrafiche/Lavorazioni/Modifica" class="btn btn-primary btn-5 d-none d-sm-inline-block">
Nuova Lavorazione
</a>
</div>
</div>
<div class="col-lg-12">
<div class="card">
<div class="table-responsive">
<RadzenDataGrid @ref="lavorazioniGrid" AllowFiltering="true" AllowColumnResize="true" AllowAlternatingRows="false" FilterMode="FilterMode.CheckBoxList" AllowSorting="true" PageSize="25"
AllowPaging="true" PagerHorizontalAlign="HorizontalAlign.Left" ShowPagingSummary="true"
Data="@lavorazioni" ColumnWidth="300px" LogicalFilterOperator="LogicalFilterOperator.Or" SelectionMode="DataGridSelectionMode.Single">
<Columns>
<RadzenDataGridColumn Property="@nameof(LavorazioneViewModel.Descrizione)" Title="Descrizione" Width="160px" />
<RadzenDataGridColumn Property="@nameof(LavorazioneViewModel.CostoOrario)" Title="Costo Orario" Width="160px" />
<RadzenDataGridColumn Property="@nameof(LavorazioneViewModel.Codice)" Title="Codice" Width="160px" />
<RadzenDataGridColumn Context="order" Filterable="false" Sortable="false" TextAlign="TextAlign.Center" Width="200px">
<Template Context="lavorazione">
<RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" class="rz-my-1 rz-ms-1" Click="@(args => EditRow(lavorazione))" @onclick:stopPropagation="true" />
<RadzenButton Icon="delete" ButtonStyle="ButtonStyle.Danger" Variant="Variant.Flat" Size="ButtonSize.Medium" Shade="Shade.Lighter" class="rz-my-1 rz-ms-1" Click="@(args => DeleteRow(lavorazione))" @onclick:stopPropagation="true" />
</Template>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
@code { @code {
List<LavorazioneViewModel> lavorazioni;
RadzenDataGrid<LavorazioneViewModel> lavorazioniGrid;
public List<BreadcrumbViewModel> BreadcrumbList { get; set; } = new();
/// <summary>
/// Carica la lista delle lavorazioni non eliminate, ordinandoli per descrizione.
/// </summary>
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
lavorazioni = (await _managerService.LavorazioneService.RicercaQueryable(
x => x.Eliminato == false,
ordinamento: x => x.OrderBy(y => y.Descrizione)))
.Select(x => (LavorazioneViewModel)x).ToList();
BreadcrumbList = await BreadcrumbUtils.BuildBreadcrumbByFeature(_managerService, "Lavorazioni_Insert");
}
/// <summary>
/// Apre la pagina di modifica per la lavorazione selezionata.
/// </summary>
private async Task EditRow(LavorazioneViewModel lavorazione)
{
_navManager.NavigateTo($"/Anagrafiche/Lavorazioni/Modifica/{lavorazione.Id}");
}
/// <summary>
/// Chiede conferma ed elimina la lavorazione; se confermato, aggiorna la lista
/// ricaricandola dal database.
/// </summary>
private async Task DeleteRow(LavorazioneViewModel lavorazione)
{
var ok = await _dialogService.Confirm($"Vuoi davvero eliminare la lavorazioen {lavorazione.Descrizione}?", "Conferma eliminazione", new ConfirmOptions { OkButtonText = "Sì", CancelButtonText = "No", Width = "400px" });
if (ok == true)
{
await _managerService.LavorazioneService.Elimina(lavorazione.Id, await MembershipUtils.GetUserId(auth));
lavorazioni = (await _managerService.LavorazioneService.RicercaQueryable(
x => x.Eliminato == false,
ordinamento: x => x.OrderBy(y => y.Descrizione)))
.Select(x => (LavorazioneViewModel)x).ToList();
}
}
} }

View File

@ -0,0 +1,134 @@
@page "/Anagrafiche/Lavorazioni/Modifica"
@page "/Anagrafiche/Lavorazioni/Modifica/{LavorazioneId:guid}"
@using TecniStamp.Domain
@using TecniStamp.Model
@using TecniStamp.Model.Common
@using TecniStamp.Utils
<PageTitle>@pageTitle</PageTitle>
<Breadcrumb Items="BreadcrumbList" />
@rendermode InteractiveServer
<div class="container-fluid h-100 mt-5">
<div class="row justify-content-start">
<div class="row row-cards">
<div class="col">
<h2 class="page-title">@pageTitle</h2>
</div>
</div>
<div class="row row-cards">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div class="row g-5">
<EditForm Model="Model" OnValidSubmit="onLavorazioneSave" FormName="editLavorazioneForm">
<DataAnnotationsValidator />
<div class="col-12">
<div class="row">
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Descrizione</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Descrizione" @bind-Value="@Model.Descrizione" />
<ValidationMessage For="@(() => Model.Descrizione)" />
</div>
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Codice</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Codice" @bind-Value="@Model.Codice" />
<ValidationMessage For="@(() => Model.Codice)" />
</div>
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Costo Orario</RadzenText>
<RadzenNumeric Style="width: 100%" Placeholder="0,00" Step="0.01" Format="0.00" aria-label="CostoOrario" @bind-Value="@Model.CostoOrario" />
<ValidationMessage For="@(() => Model.CostoOrario)" />
</div>
</div>
<div class="row">
<div class="col-4 mb-3">
<button type="button" class="btn btn-default w-100" @onclick="backToHome">
Annulla
</button>
</div>
<div class="col-4 mb-3">
<button type="submit" class="btn btn-primary w-100">
Salva
</button>
</div>
</div>
</div>
</EditForm>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@code {
[Parameter] public Guid? LavorazioneId { get; set; }
public LavorazioneViewModel Model { get; set; } = new();
private string pageTitle => Model?.Id == Guid.Empty ? "Nuova Lavorazione" : $"Modifica Lavorazione {Model.Descrizione}";
public List<BreadcrumbViewModel> BreadcrumbList { get; set; } = new();
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
Model = LavorazioneId.GetValueOrDefault() == Guid.Empty
? new LavorazioneViewModel()
: await _managerService.LavorazioneService.RicercaPer(x => x.Id == LavorazioneId);
BreadcrumbList = await BreadcrumbUtils.BuildBreadcrumbByFeature(_managerService, "Lavorazioni_Insert", "Modifica", "/Anagrafiche/Lavorazioni");
}
/// <summary>
/// Salva la lavorazione: recupera o crea il modello, applica le modifiche dalla UI
/// usando lID dellutente autenticato.
/// </summary>
private async Task onLavorazioneSave()
{
try
{
var state = await _auth.GetAuthenticationStateAsync();
var idClaim = state.User.FindFirst("UserId")?.Value;
if (string.IsNullOrEmpty(idClaim))
{
// gestisci errore (utente non autenticato o claim mancante)
return;
}
var model = await _managerService.LavorazioneService.RicercaPer(x => x.Id == Model.Id, solaLettura: false)
?? new Lavorazione();
model = Model.Map(model);
//Provvisorio
model.ChiaveEsterna = "ChiaveEsterna";
model.CodiceColore = "colore";
model.Sovrapponibile = false;
var lavorazioneSalvata = await _managerService.LavorazioneService.Salva(model, Guid.Parse(idClaim));
_navManager.NavigateTo($"/Anagrafiche/Lavorazioni");
}
catch (Exception ex)
{
await _dialogService.Alert("Si è verificato un'errore", "Errore", new AlertOptions() { OkButtonText = "Continua" });
}
}
/// <summary>
/// Torna allelenco macchinari senza applicare altre azioni.
/// </summary>
private void backToHome()
{
_navManager.NavigateTo("/Anagrafiche/Lavorazioni");
}
}

View File

@ -1,19 +1,18 @@
@page "/anagrafiche/ruoli" @page "/anagrafiche/ruoli"
@using Microsoft.EntityFrameworkCore @using Microsoft.EntityFrameworkCore
@using TecniStamp.Model @using TecniStamp.Model
@using TecniStamp.Model.Common
@using TecniStamp.Utils
@inject AuthenticationStateProvider auth
@rendermode InteractiveServer @rendermode InteractiveServer
<PageTitle>Ruoli</PageTitle> <PageTitle>Ruoli</PageTitle>
<Breadcrumb Items="BreadcrumbList" />
<div class="page-wrapper"> <main role="main">
<!-- BEGIN PAGE BODY --> <div class="container-fluid h-100 mt-5">
<div class="page-body"> <div class="row justify-content-start">
<div class="container-xl">
<div class="row row-cards"> <div class="row row-cards">
<div class="col">
<!-- Page pre-title -->
<h2 class="page-title">Ruoli</h2>
</div>
<div class="col-auto ms-auto"> <div class="col-auto ms-auto">
<div class="btn-list"> <div class="btn-list">
<a href="/Anagrafiche/Ruoli/Modifica" class="btn btn-primary btn-5 d-none d-sm-inline-block"> <a href="/Anagrafiche/Ruoli/Modifica" class="btn btn-primary btn-5 d-none d-sm-inline-block">
@ -33,7 +32,7 @@
<RadzenDataGridColumn Context="order" Filterable="false" Sortable="false" TextAlign="TextAlign.Center" Width="200px"> <RadzenDataGridColumn Context="order" Filterable="false" Sortable="false" TextAlign="TextAlign.Center" Width="200px">
<Template Context="ruolo"> <Template Context="ruolo">
<RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" class="rz-my-1 rz-ms-1" Click="@(args => EditRow(ruolo))" @onclick:stopPropagation="true" /> <RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" class="rz-my-1 rz-ms-1" Click="@(args => EditRow(ruolo))" @onclick:stopPropagation="true" />
<RadzenButton Icon="delete" ButtonStyle="ButtonStyle.Danger" Variant="Variant.Flat" Size="ButtonSize.Medium" Shade="Shade.Lighter" class="rz-my-1 rz-ms-1" @onclick:stopPropagation="true" /> <RadzenButton Icon="delete" ButtonStyle="ButtonStyle.Danger" Variant="Variant.Flat" Size="ButtonSize.Medium" Shade="Shade.Lighter" class="rz-my-1 rz-ms-1" Click="@(args => DeleteRow(ruolo))" @onclick:stopPropagation="true" />
</Template> </Template>
</RadzenDataGridColumn> </RadzenDataGridColumn>
</Columns> </Columns>
@ -44,11 +43,13 @@
</div> </div>
</div> </div>
</div> </div>
</div> </main>
@code { @code {
List<RuoloViewModel> ruoli; List<RuoloViewModel> ruoli;
RadzenDataGrid<RuoloViewModel> ruoliGrid; RadzenDataGrid<RuoloViewModel> ruoliGrid;
public List<BreadcrumbViewModel> BreadcrumbList { get; set; } = new();
/// <summary> /// <summary>
/// Carica la lista dei ruoli non eliminati, ordinandoli per nome. /// Carica la lista dei ruoli non eliminati, ordinandoli per nome.
@ -62,6 +63,8 @@
includi: x => x.Include(y => y.UtenteCreazione), includi: x => x.Include(y => y.UtenteCreazione),
ordinamento: x => x.OrderBy(y => y.Nome))) ordinamento: x => x.OrderBy(y => y.Nome)))
.Select(x => (RuoloViewModel)x).ToList(); .Select(x => (RuoloViewModel)x).ToList();
BreadcrumbList = await BreadcrumbUtils.BuildBreadcrumbByFeature(_managerService, "ruoli_Insert");
} }
/// <summary> /// <summary>
@ -71,4 +74,22 @@
{ {
_navManager.NavigateTo($"/Anagrafiche/ruoli/Modifica/{ruolo.Id}"); _navManager.NavigateTo($"/Anagrafiche/ruoli/Modifica/{ruolo.Id}");
} }
/// <summary>
/// Chiede conferma ed elimina lutente; se confermato, aggiorna la lista
/// ricaricandola dal database.
/// </summary>
private async Task DeleteRow(RuoloViewModel ruolo)
{
var ok = await _dialogService.Confirm($"Vuoi davvero eliminare il ruolo {ruolo.Nome}?", "Conferma eliminazione", new ConfirmOptions { OkButtonText = "Sì", CancelButtonText = "No", Width = "400px" });
if (ok == true)
{
await _managerService.RuoloService.Elimina(ruolo.Id, await MembershipUtils.GetUserId(auth));
ruoli = (await _managerService.RuoloService.RicercaQueryable(
x => x.Eliminato == false,
ordinamento: x => x.OrderBy(y => y.Nome)))
.Select(x => (RuoloViewModel)x).ToList();
}
}
} }

View File

@ -3,10 +3,12 @@
@using Microsoft.EntityFrameworkCore @using Microsoft.EntityFrameworkCore
@using TecniStamp.Domain @using TecniStamp.Domain
@using TecniStamp.Model @using TecniStamp.Model
@using TecniStamp.Model.Common
@using TecniStamp.Utils @using TecniStamp.Utils
@rendermode InteractiveServer @rendermode InteractiveServer
@inject AuthenticationStateProvider auth @inject AuthenticationStateProvider auth
<Breadcrumb Items="BreadcrumbList" />
<PageTitle>@pageTitle</PageTitle> <PageTitle>@pageTitle</PageTitle>
@ -24,7 +26,7 @@
<!-- END PAGE HEADER --> <!-- END PAGE HEADER -->
<!-- BEGIN PAGE BODY --> <!-- BEGIN PAGE BODY -->
<div class="page-body"> <div class="page-body">
<div class="container-xl"> <div class="container-fluid">
<div class="row row-cards"> <div class="row row-cards">
<div class="col-lg-12"> <div class="col-lg-12">
@ -95,6 +97,7 @@
public RuoloViewModel Model { get; set; } = new(); public RuoloViewModel Model { get; set; } = new();
private List<PermissionRowViewModel> permessi { get; set; } = new(); private List<PermissionRowViewModel> permessi { get; set; } = new();
private RadzenDataGrid<PermissionRowViewModel> permessiGrid { get; set; } private RadzenDataGrid<PermissionRowViewModel> permessiGrid { get; set; }
public List<BreadcrumbViewModel> BreadcrumbList { get; set; } = new();
private string pageTitle => Model?.Id == Guid.Empty ? "Nuovo Ruolo" : $"Modifica Ruolo {Model}"; private string pageTitle => Model?.Id == Guid.Empty ? "Nuovo Ruolo" : $"Modifica Ruolo {Model}";
@ -113,6 +116,8 @@
permessi = []; permessi = [];
foreach (var section in sections) foreach (var section in sections)
permessi.AddRange(section.Features.Where(x => !x.Eliminato).Select(x => new PermissionRowViewModel(section, x, permissions)).ToList()); permessi.AddRange(section.Features.Where(x => !x.Eliminato).Select(x => new PermissionRowViewModel(section, x, permissions)).ToList());
BreadcrumbList = await BreadcrumbUtils.BuildBreadcrumbByFeature(_managerService, "Ruoli_Insert", "Modifica", "/Anagrafiche/Ruoli");
} }
/// <summary> /// <summary>

View File

@ -0,0 +1,53 @@
using System.ComponentModel.DataAnnotations;
using TecniStamp.Domain;
namespace TecniStamp.Model;
public class LavorazioneViewModel : BaseViewModel
{
[Required(ErrorMessage = "La descrizione è obbligatoria")]
public string Descrizione { get; set; }
[Required(ErrorMessage = "il costo orario è obbligatorio")]
public float? CostoOrario { get; set; }
[Required(ErrorMessage = "il codice è obbligatorio")]
public string Codice { get; set; }
public string ChiaveEsterna { get; set; }
public string CodiceColore { get; set; }
public bool Sovrapponibile { get; set; }
public override void Validate()
{
}
public static implicit operator LavorazioneViewModel(Lavorazione model)
{
return model == null
? null
: new LavorazioneViewModel()
{
Id = model.Id,
Descrizione = model.Descrizione,
CostoOrario = model.CostoOrario,
Codice = model.Codice,
ChiaveEsterna = model.ChiaveEsterna,
CodiceColore = model.CodiceColore,
Sovrapponibile = model.Sovrapponibile
};
}
public Lavorazione Map(Lavorazione model)
{
model.Descrizione = Descrizione;
model.CostoOrario = CostoOrario;
model.Codice = Codice;
model.ChiaveEsterna = ChiaveEsterna;
model.Sovrapponibile = Sovrapponibile;
model.CodiceColore = CodiceColore;
return model;
}
}