- Import Comuni

- Permessi modifica agente/capoarea in Clienti
This commit is contained in:
2025-12-22 15:05:07 +01:00
parent 1f87913904
commit c08e9325b4
11 changed files with 234 additions and 61 deletions

View File

@ -0,0 +1,16 @@
using OAService.Service.Servizi.Implementazioni;
using StandManager.Domain.Entita;
using StandManager.Service.Interfaces;
using StandManager.Service.Repository;
namespace StandManager.Service;
public class ComuneIstatService : TService<ComuneIstat>, IComuneIstatService
{
private readonly IStandManagerUnitOfWork _unitOfWork;
public ComuneIstatService(IStandManagerUnitOfWork unitOfWork) : base(unitOfWork)
{
_unitOfWork = unitOfWork;
}
}

View File

@ -0,0 +1,8 @@
using OAService.Service.Servizi.Interfacce;
using StandManager.Domain.Entita;
namespace StandManager.Service.Interfaces;
public interface IComuneIstatService : ITService<ComuneIstat>
{
}

View File

@ -3,6 +3,7 @@
public interface IManagerService
{
public IClienteService ClienteService{ get; set; }
public IComuneIstatService ComuneIstatService { get; set; }
public IDestinazioneService DestinazioneService{ get; set; }
public IEventoService EventoService{ get; set; }
public IFeatureService FeatureService{ get; set; }

View File

@ -4,12 +4,13 @@ namespace StandManager.Service;
public class ManagerService : IManagerService
{
public ManagerService(IUtenteService utenteService, IClienteService clienteService, IDestinazioneService destinazioneService, IEventoService eventoService,
public ManagerService(IUtenteService utenteService, IClienteService clienteService, IComuneIstatService comuneIstatService, IDestinazioneService destinazioneService, IEventoService eventoService,
IInvitoEventoService invitoEventoService, IIscrizioneEventoService iscrizioneEventoService, IReferenteService referenteService,
ITipologiaClienteService tipologiaClienteService, IFeatureService featureService, IPermissionService permissionService, IRuoloService ruoloService, ISezioneService sezioneService)
{
UtenteService = utenteService;
ClienteService = clienteService;
ComuneIstatService = comuneIstatService;
DestinazioneService = destinazioneService;
EventoService = eventoService;
InvitoEventoService = invitoEventoService;
@ -34,4 +35,5 @@ public class ManagerService : IManagerService
public IRuoloService RuoloService { get; set; }
public ISezioneService SezioneService { get; set; }
public ITipologiaClienteService TipologiaClienteService { get; set; }
public IComuneIstatService ComuneIstatService { get; set; }
}

View File

@ -57,7 +57,7 @@
<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=@destinazione.AgenteId Data=@agenti TextProperty="Info" ValueProperty="Id" Name="agenteDestDrop" />
<RadzenDropDown Style="width: 100%" TValue="Guid ?" @bind-Value=@destinazione.AgenteId Data=@agenti TextProperty="Info" ValueProperty="Id" Name="agenteDestDrop" Disabled="@(!canSetAgente)" />
</div>
</div>
@ -79,6 +79,8 @@
@code {
[Parameter] public Guid destinazioneId { get; set; } = Guid.Empty;
[Parameter] public Guid clienteId { get; set; } = Guid.Empty;
[Parameter] public bool canSetAgente { get; set; } = false;
[Parameter] public Guid capoareaId { get; set; } = Guid.Empty;
private DestinazioneViewModel destinazione { get; set; } = new();
private IEnumerable<UtenteViewModel> agenti { get; set; } = new List<UtenteViewModel>();
@ -91,8 +93,8 @@
protected override async Task OnInitializedAsync()
{
base.OnInitializedAsync();
agenti = (await _managerService.UtenteService.RicercaQueryable(x => x.Eliminato == false, ordinamento: x => x.OrderBy(y => y.Cognome).ThenBy(z => z.Nome)))
agenti = (await _managerService.UtenteService.RicercaQueryable(x => x.Eliminato == false && !x.IsCapoarea && x.CapoareaId == capoareaId, ordinamento: x => x.OrderBy(y => y.Cognome).ThenBy(z => z.Nome)))
.Select(x => (UtenteViewModel)x).ToList();
destinazione = destinazioneId == Guid.Empty ? new() : await _managerService.DestinazioneService.RicercaPer(x => x.Id == destinazioneId,

View File

@ -25,6 +25,8 @@
<div class="btn-list">
<RadzenUpload class="btn-5 d-none d-sm-inline-block" Change=@onUpload ChooseText="Importa da excel" />
<RadzenUpload class="btn-5 d-none d-sm-inline-block" Change=@onUploadComuni ChooseText="Importa comuni da excel" />
<a href="/management/Clienti/Modifica" class="btn btn-primary btn-5 d-none d-sm-inline-block">
Nuovo cliente
</a>
@ -122,4 +124,25 @@
await _dialogService.Alert("Si è verificato un errore durante l'importazione del file.", "Errore");
}
}
private async Task onUploadComuni(UploadChangeEventArgs args)
{
var file = args.Files.FirstOrDefault();
if (file == null ||
!file.Name.EndsWith(".xlsx", StringComparison.OrdinalIgnoreCase))
{
await _dialogService.Alert("Sono supportati solo file Excel .xlsx", "Errore");
return;
}
try
{
// await using var uploadStream = file.OpenReadStream(10_000_000);
await _dialogService.OpenAsync<Comuni_Import>("Importazione comuni", new Dictionary<string, object>() { { "args", args } });
}
catch (Exception ex)
{
var er = ex.Message;
await _dialogService.Alert("Si è verificato un errore durante l'importazione del file.", "Errore");
}
}
}

View File

@ -64,31 +64,13 @@
</div>
<div class="row">
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Cap</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Nome" @bind-Value="@cliente.Cap" />
</div>
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Citta</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Cognome" @bind-Value="@cliente.Citta" />
</div>
<div class="col-3 mb-3">
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Indirizzo</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Email" @bind-Value="@cliente.Indirizzo" />
</div>
<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>
<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" />
<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>
@ -98,9 +80,16 @@
<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">Tipologia Gestionale</RadzenText>
<RadzenTextBox Style="width: 100%" aria-label="Email" @bind-Value="@cliente.TipologiaGestionale" />
<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>
@ -179,10 +168,14 @@
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()
@ -205,23 +198,34 @@
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));
var isAdmin = ruolo?.Permessi.Where(x => x.Eliminato == false)?.Any(x => x.Feature.Type == FeatureType.AdminGlobal) ?? false;
agenti = ruolo == null
? [await _managerService.UtenteService.RicercaPer(x => x.Id == idClaim)]
: (await _managerService.UtenteService.RicercaQueryable(
x => x.Eliminato == false && (isAdmin || x.CapoareaId == idClaim),
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();
.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>();
if (ClienteId.GetValueOrDefault() != Guid.Empty)
cliente = await _managerService.ClienteService.RicercaPer(x => x.Id == ClienteId, includi: x => x.Include(y => y.Agente).Include(y => y.TipologiaCliente).Include(y => y.Destinazioni).ThenInclude(z => z.Agente));
else
cliente = new ClienteViewModel();
_dialogService.OnClose += onDialogClose;
}
@ -279,7 +283,7 @@
/// </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 } }, editNewDialogOption);
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>
@ -287,7 +291,7 @@
/// </summary>
private async Task onNuovaDestinazionePressed()
{
await _dialogService.OpenAsync<Cliente_Destinazione>($"Nuova destinazione", new Dictionary<string, object>() { { "clienteId", cliente.Id } }, editNewDialogOption);
await _dialogService.OpenAsync<Cliente_Destinazione>($"Nuova destinazione", new Dictionary<string, object>() { { "clienteId", cliente.Id }, { "canSetAgente", (cliente.CapoareaId == idClaim) || isAdmin }, { "capoareaId", capoareaId } }, editNewDialogOption);
}
/// <summary>
@ -305,4 +309,26 @@
.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)];
}
}
}

View File

@ -41,24 +41,22 @@
var codiciAgente = rows.Select(r => new { CodiceAgente = r.Agente, Nome = r.DescrizioneAgente, Capoarea = r.CapoArea }).Distinct().ToList();
var codiciCapoarea = rows.Select(r => new { CodiceCapoarea = r.CapoArea, Nome = r.DescrizioneCapoArea }).Distinct().ToList();
var capoareaList = await _managerService.UtenteService.ListaCapoarea();
foreach (var fileCapoarea in codiciCapoarea)
{
var capoarea = await _managerService.UtenteService.RicercaPer(x => x.CodiceAgente == fileCapoarea.CodiceCapoarea);
if ((capoarea?.Id ?? new Guid()) != Guid.Empty)
continue;
capoarea = await mapCapoArea(new Utente(), fileCapoarea.CodiceCapoarea, fileCapoarea.Nome);
var capoarea = await _managerService.UtenteService.RicercaPer(x => x.CodiceAgente == fileCapoarea.CodiceCapoarea, solaLettura: false);
capoarea = await mapCapoArea(capoarea ?? new Utente(), fileCapoarea.CodiceCapoarea, fileCapoarea.Nome);
await _managerService.UtenteService.Salva(capoarea, idClaim);
capoareaList.Add(capoarea);
}
var capoareaList = await _managerService.UtenteService.ListaCapoarea();
foreach (var fileAgente in codiciAgente)
{
var agente = await _managerService.UtenteService.RicercaPer(x => x.CodiceAgente == fileAgente.CodiceAgente);
if ((agente?.Id ?? new Guid()) != Guid.Empty)
continue;
var agente = await _managerService.UtenteService.RicercaPer(x => x.CodiceAgente == fileAgente.CodiceAgente, solaLettura: false);
// if ((agente?.Id ?? new Guid()) != Guid.Empty)
// continue;
var capoarea = capoareaList.FirstOrDefault(x => x.CodiceAgente == fileAgente.Capoarea);
agente = await mapAgente(new Utente(), fileAgente.CodiceAgente, fileAgente.Nome, capoarea.Id);
agente = await mapAgente(agente ?? new Utente(), fileAgente.CodiceAgente, fileAgente.Nome, capoarea?.Id);
await _managerService.UtenteService.Salva(agente, idClaim);
}
@ -95,15 +93,9 @@
model.Rid = firstRow.CodCli;
model.RagioneSociale = firstRow.RagSocCliente;
model.PartitaIva = firstRow.PartitaIva;
/*var agente = await _managerService.UtenteService.RicercaPer(filtro: x => x.CodiceAgente == firstRow.Agente && x.Eliminato == false, solaLettura: false) ?? new Utente();
agente = await mapAgente(agente, firstRow, model.CapoareaId);
if (agente.Id == Guid.Empty) agente.Password = "";
var savedAgente = await _managerService.UtenteService.Salva(agente, idClaim);
model.AgenteId = savedAgente.Id;*/
// TODO: Problema nel salvataggio delle destinazioni
// TODO: TipologiaCliente da inserire (pesco a db)
model.Destinazioni ??= new();
foreach (var destinazioneRiga in rows)
{
var destinazione = model.Destinazioni.FirstOrDefault(x => x.Rid == destinazioneRiga.CodDes) ?? new Destinazione();
@ -117,6 +109,8 @@
private async Task<Destinazione> mapDestinazione(Destinazione model, Guid clienteId, ClienteExcelViewModel row, Guid? agenteId)
{
// TODO: Comune da inserire (pesco a db)
model.Rid = row.CodDes;
model.RagioneSociale = row.RagSocDestinazione;
model.PartitaIva = row.PartitaIva;
@ -150,10 +144,10 @@
model.Username = nome;
model.CodiceAgente = codice;
model.Nome = nome;
model.Cognome = "";
model.Email = "";
model.Cognome = string.Empty;
model.Email = string.Empty;
model.Password = string.Empty;
/*model.CapoareaId = capoareaId;*/
model.CapoareaId = capoareaId;
return model;
}

View File

@ -0,0 +1,73 @@
@using ClosedXML.Excel
@using Microsoft.EntityFrameworkCore
@using StandManager.Model
@attribute [Authorize]
@rendermode InteractiveServer
@inject AuthenticationStateProvider auth
<RadzenStack Gap="1rem" class="rz-m-12">
<RadzenProgressBar Value="@counter" Max="@comuniTotali" Unit="@counterLabel" AriaLabel="" />
</RadzenStack>
@code {
[CascadingParameter] private Dialog _dialog { get; set; }
[Parameter] public UploadChangeEventArgs args { get; set; }
private int comuniTotali { get; set; } = 0;
private int counter { get; set; } = 0;
private string counterLabel { get; set; } = string.Empty;
protected override async Task OnInitializedAsync()
{
base.OnInitializedAsync();
var file = args.Files.FirstOrDefault();
await using var uploadStream = file.OpenReadStream(10_000_000);
var idClaim = await MembershipUtils.GetUserId(auth);
await using var ms = new MemoryStream();
await uploadStream.CopyToAsync(ms);
ms.Position = 0;
using var workbook = new XLWorkbook(ms);
var ws = workbook.Worksheet(1);
var usedRange = ws.RangeUsed();
var rows = new List<ComuneIstatExcelViewModel>(usedRange.RowCount() - 1);
foreach (var row in usedRange.RowsUsed().Skip(1))
rows.Add(new ComuneIstatExcelViewModel(row));
var comuni = rows.ToList();
comuniTotali = comuni.Count;
counterLabel = " di " + comuniTotali;
foreach (var comune in comuni)
{
var comuneDb = await _managerService.ComuneIstatService.RicercaPer(
x => x.Istat == comune.Istat && x.Eliminato == false,
solaLettura: false) ?? new ComuneIstat();
comuneDb = await mapComune(comuneDb, comune);
await _managerService.ComuneIstatService.Salva(comuneDb, idClaim);
counter += 1;
StateHasChanged();
}
ms.Close();
_dialogService.Close();
}
private async Task<ComuneIstat> mapComune(ComuneIstat model, ComuneIstatExcelViewModel row)
{
model.Istat = row.Istat;
model.Comune = row.Comune;
model.Regione = row.Regione;
model.Provincia = row.Provincia;
model.Prefisso = row.Prefisso;
model.CodFisco = row.CodFisco;
return model;
}
}

View File

@ -20,6 +20,8 @@ public class ClienteViewModel
public string NomeCapoarea { get; set; }
public Guid? AgenteId { get; set; }
public UtenteViewModel Agente { get; set; }
public Guid? CapoareaId { get; set; }
public UtenteViewModel Capoarea { get; set; }
public List<DestinazioneViewModel> Destinazioni { get; set; }
public string Rid { get; set; }
@ -39,6 +41,8 @@ public class ClienteViewModel
NomeCapoarea = model.Capoarea?.Nome.ToString(),
Agente = model.Agente,
AgenteId = model.AgenteId,
Capoarea = model.Capoarea,
CapoareaId = model.CapoareaId,
Cap = model.Cap,
Citta = model.Citta,
Email = model.Email,

View File

@ -0,0 +1,24 @@
using ClosedXML.Excel;
namespace StandManager.Model;
public class ComuneIstatExcelViewModel
{
public ComuneIstatExcelViewModel(IXLRangeRow row)
{
Istat = row.Cell(1).GetString();
Comune = row.Cell(2).GetString();
Regione = row.Cell(3).GetString();
Provincia = row.Cell(4).GetString();
Prefisso = row.Cell(5).GetString();
CodFisco = row.Cell(6).GetString();
}
public string Istat { get; set; }
public string Comune { get; set; }
public string Regione { get; set; }
public string Provincia { get; set; }
public string Prefisso { get; set; }
public string CodFisco { get; set; }
}