Files
StandManager/StandManager/Components/Pages/Management/Clienti_Edit.razor
Davide Sandrelli c08e9325b4 - Import Comuni
- Permessi modifica agente/capoarea in Clienti
2025-12-22 15:05:07 +01:00

335 lines
19 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@attribute [Authorize]
@rendermode InteractiveServer
@page "/management/Clienti/Modifica"
@page "/management/Clienti/Modifica/{ClienteId:guid}"
@using Microsoft.AspNetCore.Identity
@using Microsoft.EntityFrameworkCore
@using StandManager.Model
@inject AuthenticationStateProvider auth
<PageTitle>@pageTitle</PageTitle>
<div class="page-wrapper">
<!-- BEGIN PAGE HEADER -->
<div class="page-header d-print-none" aria-label="Page header">
<div class="container-xl">
<div class="row g-2 align-items-center">
<div class="col">
<h2 class="page-title">@pageTitle</h2>
</div>
</div>
</div>
</div>
<!-- END PAGE HEADER -->
<!-- BEGIN PAGE BODY -->
<div class="page-body">
<div class="container-xl">
<div class="row row-cards">
<div class="col-lg-12">
<div class="card">
<div class="card-header">
Anagrafica
</div>
<div class="card-body">
<div class="row g-5">
<EditForm Model="cliente" OnValidSubmit="onClienteSave" FormName="editClienteForm">
<DataAnnotationsValidator />
<div class="col-12">
<div class="row">
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Ragione Sociale</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Nome" @bind-Value="@cliente.RagioneSociale" />
<ValidationMessage For="@(() => cliente.RagioneSociale)" />
</div>
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Partita Iva</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Cognome" @bind-Value="@cliente.PartitaIva" />
<ValidationMessage For="@(() => cliente.PartitaIva)" />
</div>
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Email</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Email" @bind-Value="@cliente.Email" />
</div>
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Numero di Telefono</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Email" @bind-Value="@cliente.NumeroTelefono" />
</div>
</div>
<div class="row">
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Email di invito</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Email" @bind-Value="@cliente.EmailInvito" />
</div>
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Tipologia Gestionale</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Email" @bind-Value="@cliente.TipologiaGestionale" />
</div>
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Tipologia</RadzenText>
<RadzenDropDown Style="width: 100%" TValue="Guid ?" @bind-Value=@cliente.TipologiaClienteId Data=@tipologiaCliente TextProperty="Nome" ValueProperty="Id" Name="tipologiaClienteDrop" />
</div>
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Stato</RadzenText>
<RadzenDropDown Style="width: 100%" TValue="int" @bind-Value=@cliente.StatoClienteInt Data=@statoCliente TextProperty="Description" ValueProperty="Key" Name="statoClienteDrop" />
</div>
</div>
<div class="row">
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Agente</RadzenText>
<RadzenDropDown Style="width: 100%" TValue="Guid ?" @bind-Value=@cliente.AgenteId Data=@agenti TextProperty="Info" ValueProperty="Id" Name="agenteDrop" Disabled="@(!(cliente.CapoareaId == idClaim) && !isAdmin)" />
</div>
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Capoarea</RadzenText>
<RadzenDropDown Style="width: 100%" TValue="Guid ?" @bind-Value=@cliente.CapoareaId Data=@capiarea TextProperty="Info" ValueProperty="Id" Name="capoareaDrop" Disabled="!isAdmin" Change="(x => OnCapoareaChange(x))" />
</div>
</div>
<div class="row">
<div class="col-3 mb-3">
<button type="button" class="btn btn-default w-100" @onclick="backToHome">
Annulla
</button>
</div>
<div class="col-3 mb-3">
<button type="submit" class="btn btn-primary w-100">
Salva
</button>
</div>
</div>
</div>
</EditForm>
</div>
</div>
</div>
</div>
@if (cliente.Id != Guid.Empty)
{
<div class="col-lg-12">
<div class="card">
<div class="card-header">
Destinazioni
</div>
<div class="card-body">
<div class="row g-5">
<div class="col-auto ms-auto">
<div class="btn-list">
<RadzenButton ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" Click="@(args => onNuovaDestinazionePressed())" @onclick:stopPropagation="true" Text="Nuova destinazione"></RadzenButton>
</div>
</div>
<div class="table-responsive">
<RadzenDataGrid @ref="destinazioniGrid" AllowFiltering="true" AllowColumnResize="true" AllowAlternatingRows="false" FilterMode="FilterMode.CheckBoxList" AllowSorting="true" PageSize="5"
AllowPaging="true" PagerHorizontalAlign="HorizontalAlign.Left" ShowPagingSummary="true"
Data="@cliente.Destinazioni" LogicalFilterOperator="LogicalFilterOperator.Or" SelectionMode="DataGridSelectionMode.Single">
<Columns>
<RadzenDataGridColumn Property="@nameof(DestinazioneViewModel.Id)" Filterable="false" Title="ID" Width="80px" TextAlign="TextAlign.Center" />
<RadzenDataGridColumn Property="@nameof(DestinazioneViewModel.RagioneSociale)" Title="Ragione sociale" Width="200px" />
<RadzenDataGridColumn Property="@nameof(DestinazioneViewModel.PartitaIva)" Title="Partita IVA" Width="200px" />
<RadzenDataGridColumn Property="@nameof(DestinazioneViewModel.Cap)" Title="Cap" Width="100px" />
<RadzenDataGridColumn Property="@nameof(DestinazioneViewModel.Citta)" Title="Citta" Width="150px" />
<RadzenDataGridColumn Property="@nameof(DestinazioneViewModel.Indirizzo)" Title="Indirizzo" Width="200px" />
<RadzenDataGridColumn Property="@nameof(DestinazioneViewModel.NomeAgente)" Title="Agente" Width="200px" />
<RadzenDataGridColumn Context="destinazione" Filterable="false" Sortable="false" TextAlign="TextAlign.Right" Width="200px">
<Template Context="destinazione">
<RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" class="rz-my-1 rz-ms-1" Click="@(args => EditDestinazione(destinazione))" @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 => DeleteDestinazione(destinazione))" @onclick:stopPropagation="true" />
</Template>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>
</div>
</div>
</div>
</div>
</div>
}
</div>
</div>
</div>
</div>
@code {
[Parameter]
public Guid? ClienteId { get; set; }
public Guid idClaim { get; set; }
[SupplyParameterFromForm]
private ClienteViewModel cliente { get; set; } = new();
private IEnumerable<UtenteViewModel> agenti { get; set; } = new List<UtenteViewModel>();
private IEnumerable<UtenteViewModel> capiarea { get; set; } = new List<UtenteViewModel>();
private List<TipologiaClienteViewModel> tipologiaCliente { get; set; } = new();
private List<LookupViewModel<int>> statoCliente { get; set; } = new();
RadzenDataGrid<DestinazioneViewModel> destinazioniGrid;
private bool isAdmin { get; set; } = false;
private Guid capoareaId { get; set; } = Guid.Empty;
private string pageTitle => cliente?.Id == Guid.Empty ? "Nuovo cliente" : "Modifica cliente";
private DialogOptions editNewDialogOption { get; set; } = new()
{
Resizable = false,
Draggable = false,
Width = "900px"
};
/// <summary>
/// Inizializza la pagina: carica gli agenti, le tipologie cliente
/// e, se presente lID, recupera il cliente con agente e destinazioni,
/// registrando anche levento di chiusura del dialog.
/// </summary>
protected override async Task OnInitializedAsync()
{
idClaim = await MembershipUtils.GetUserId(auth);
var idRuolo = await MembershipUtils.GetRoleId(auth);
var ruolo = await _managerService.RuoloService.RicercaPer(
x => x.Id == idRuolo && x.Permessi.Any(y => y.Feature.Type == FeatureType.Capoarea || y.Feature.Type == FeatureType.AdminGlobal),
includi:x => x.Include(y => y.Permessi).ThenInclude(z => z.Feature));
isAdmin = ruolo?.Permessi.Where(x => x.Eliminato == false)?.Any(x => x.Feature.Type == FeatureType.AdminGlobal) ?? false;
if (ClienteId.GetValueOrDefault() != Guid.Empty)
cliente = await _managerService.ClienteService.RicercaPer(x => x.Id == ClienteId, includi: x => x.Include(y => y.Agente).Include(y => y.Capoarea).Include(y => y.TipologiaCliente).Include(y => y.Destinazioni).ThenInclude(z => z.Agente));
else
cliente = new ClienteViewModel();
capoareaId = cliente.CapoareaId.GetValueOrDefault();
capiarea = isAdmin
? (await _managerService.UtenteService.RicercaQueryable(
x => x.Eliminato == false && x.IsCapoarea,
ordinamento: x => x.OrderBy(y => y.Cognome).ThenBy(z => z.Nome)))
.Select(x => (UtenteViewModel)x).ToList()
: [await _managerService.UtenteService.RicercaPer(x => x.Id == cliente.CapoareaId)];
agenti = cliente.CapoareaId == idClaim || isAdmin
? (await _managerService.UtenteService.RicercaQueryable(
x => x.Eliminato == false && (isAdmin || x.CapoareaId == idClaim) && !x.IsCapoarea && x.CapoareaId == cliente.CapoareaId,
includi: x => x.Include(y => y.Capoarea),
ordinamento: x => x.OrderBy(y => y.Cognome).ThenBy(z => z.Nome)))
.Select(x => (UtenteViewModel)x).ToList()
: [await _managerService.UtenteService.RicercaPer(x => x.Id == cliente.AgenteId)];
var eUtils = new EnumUtils();
tipologiaCliente = (await _managerService.TipologiaClienteService.RicercaQueryable(ordinamento: x => x.OrderBy(y => y.Nome))).Select(x => (TipologiaClienteViewModel)x).ToList();
statoCliente = eUtils.GetEnumList<ClienteStato>();
_dialogService.OnClose += onDialogClose;
}
/// <summary>
/// Alla chiusura del dialog ricarica da database le destinazioni
/// del cliente aggiornando la lista in schermata.
/// </summary>
private async void onDialogClose(dynamic result)
{
cliente.Destinazioni = (await _managerService.DestinazioneService.RicercaQueryable(x => x.Eliminato == false && x.ClienteId == cliente.Id, includi: x => x.Include(y => y.Agente)))
.Select(x => (DestinazioneViewModel)x).ToList();
}
/// <summary>
/// Salva il cliente: recupera o crea il modello, applica i dati dalla UI,
/// collega lagente, crea una destinazione di default se è un nuovo cliente
/// e poi salva usando lID dellutente loggato, tornando alla lista clienti.
/// </summary>
private async Task onClienteSave()
{
var model = await _managerService.ClienteService.RicercaPer(x => x.Id == cliente.Id, solaLettura: false)
?? new Cliente() { Destinazioni = new List<Destinazione>() };
model = cliente.Map(model);
if (cliente.AgenteId.GetValueOrDefault() != Guid.Empty)
model.Agente = await _managerService.UtenteService.RicercaPer(x => x.Id == cliente.AgenteId);
if (cliente.TipologiaClienteId.GetValueOrDefault() != Guid.Empty)
{
model.TipologiaClienteId = cliente.TipologiaClienteId;
model.TipologiaCliente = await _managerService.TipologiaClienteService.RicercaPer(x => x.Id == cliente.TipologiaClienteId);
}
if (cliente.Id == Guid.Empty)
{
var destinazione = new Destinazione() { Cliente = model };
destinazione = cliente.GetDestinazione(destinazione);
model.Destinazioni.Add(destinazione);
}
await _managerService.ClienteService.Salva(model, idClaim);
_navManager.NavigateTo("/management/Clienti");
}
/// <summary>
/// Torna alla pagina di elenco clienti senza salvare altre modifiche.
/// </summary>
private void backToHome()
{
_navManager.NavigateTo("/management/Clienti");
}
/// <summary>
/// Apre il dialog di modifica per la destinazione selezionata.
/// </summary>
private async Task EditDestinazione(DestinazioneViewModel destinazione)
{
await _dialogService.OpenAsync<Cliente_Destinazione>($"Destinazione {destinazione.RagioneSociale}", new Dictionary<string, object>() { { "destinazioneId", destinazione.Id }, { "clienteId", cliente.Id }, { "canSetAgente", (cliente.CapoareaId == idClaim) || isAdmin }, { "capoareaId", capoareaId } }, editNewDialogOption);
}
/// <summary>
/// Apre il dialog per creare una nuova destinazione collegata al cliente.
/// </summary>
private async Task onNuovaDestinazionePressed()
{
await _dialogService.OpenAsync<Cliente_Destinazione>($"Nuova destinazione", new Dictionary<string, object>() { { "clienteId", cliente.Id }, { "canSetAgente", (cliente.CapoareaId == idClaim) || isAdmin }, { "capoareaId", capoareaId } }, editNewDialogOption);
}
/// <summary>
/// Chiede conferma, elimina la destinazione scelta se confermato
/// e ricarica lelenco delle destinazioni del cliente.
/// </summary>
private async Task DeleteDestinazione(DestinazioneViewModel destinazione)
{
var ok = await _dialogService.Confirm($"Vuoi davvero eliminare la destinazione {cliente.RagioneSociale}?", "Conferma eliminazione", new ConfirmOptions { OkButtonText = "Sì", CancelButtonText = "No", Width = "400px" });
if (ok == true)
{
await _managerService.DestinazioneService.Elimina(destinazione.Id, await MembershipUtils.GetUserId(auth));
cliente.Destinazioni = (await _managerService.DestinazioneService.RicercaQueryable(x => x.Eliminato == false && x.ClienteId == cliente.Id, includi: x => x.Include(y => y.Agente)))
.Select(x => (DestinazioneViewModel)x).ToList();
}
}
/// <summary>
/// Aggiorna la drop di agenti in base al valore di capoarea
/// </summary>
private async Task OnCapoareaChange(object value)
{
var capoId = Guid.Empty;
if (Guid.TryParse(value.ToString(), out capoId))
{
capoareaId = capoId;
cliente.AgenteId = null;
agenti = cliente.CapoareaId == idClaim || isAdmin
? (await _managerService.UtenteService.RicercaQueryable(
x => x.Eliminato == false && (isAdmin || x.CapoareaId == idClaim) && !x.IsCapoarea && x.CapoareaId == capoareaId,
includi: x => x.Include(y => y.Capoarea),
ordinamento: x => x.OrderBy(y => y.Cognome).ThenBy(z => z.Nome)))
.Select(x => (UtenteViewModel)x).ToList()
: [await _managerService.UtenteService.RicercaPer(x => x.Id == cliente.AgenteId)];
}
}
}