Add Professional y Specialty on API UI
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 5m31s
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 5m31s
This commit is contained in:
parent
319f7234c5
commit
f4d6bd9e28
17
Core/Interfaces/IProfessionalDom.cs
Normal file
17
Core/Interfaces/IProfessionalDom.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using Domain.Entities;
|
||||||
|
using Domain.Generics;
|
||||||
|
|
||||||
|
namespace Core.Interfaces
|
||||||
|
{
|
||||||
|
public interface IProfessionalDom
|
||||||
|
{
|
||||||
|
Task<EProfessional> CreateAsync(EProfessional entity);
|
||||||
|
Task<bool> DeleteAsync(int id);
|
||||||
|
Task<byte[]> ExportFilteredProfessionalsToExcelAsync(ProfessionalSearchParams searchParams);
|
||||||
|
Task<PagedResult<EProfessional>> GetAllAsync(int page = 1, int pageSize = 50);
|
||||||
|
Task<EProfessional?> GetByIdAsync(int id);
|
||||||
|
Task<PagedResult<EProfessional>> SearchAsync(string? fullname, string? document, string? type,
|
||||||
|
int page = 1, int pageSize = 50);
|
||||||
|
Task<bool> UpdateAsync(EProfessional entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Core/Interfaces/IProfessionalSpecialtyDom.cs
Normal file
10
Core/Interfaces/IProfessionalSpecialtyDom.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using Domain.Entities;
|
||||||
|
|
||||||
|
namespace Core.Interfaces
|
||||||
|
{
|
||||||
|
public interface IProfessionalSpecialtyDom
|
||||||
|
{
|
||||||
|
Task<IEnumerable<EProfessionalSpecialty>> GetAllAsync();
|
||||||
|
Task<EProfessionalSpecialty?> GetByNameAsync(string name);
|
||||||
|
}
|
||||||
|
}
|
||||||
145
Core/Services/ProfessionalService.cs
Normal file
145
Core/Services/ProfessionalService.cs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
using Core.Interfaces;
|
||||||
|
using Domain.Entities;
|
||||||
|
using Domain.Generics;
|
||||||
|
using Models.Interfaces;
|
||||||
|
using System.Reflection;
|
||||||
|
using Transversal.Services;
|
||||||
|
|
||||||
|
namespace Core.Services
|
||||||
|
{
|
||||||
|
public class ProfessionalService : IProfessionalDom
|
||||||
|
{
|
||||||
|
#region Declaraciones y Constructor
|
||||||
|
private readonly IPhSProfessionalRepository _repository;
|
||||||
|
|
||||||
|
public ProfessionalService(IPhSProfessionalRepository professionalRepository)
|
||||||
|
{
|
||||||
|
_repository = professionalRepository ?? throw new ArgumentNullException(nameof(professionalRepository));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region Métodos
|
||||||
|
public async Task<PagedResult<EProfessional>> GetAllAsync(int page = 1, int pageSize = 50)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _repository.GetAllAsync(page, pageSize);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var method = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
throw new Exception($"{method} Message: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<EProfessional?> GetByIdAsync(int id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _repository.GetByIdAsync(id);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var method = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
throw new Exception($"{method} Message: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<EProfessional> CreateAsync(EProfessional entity)
|
||||||
|
{
|
||||||
|
if (entity is null)
|
||||||
|
throw new ArgumentNullException(nameof(entity), "El profesional no puede ser nulo.");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(entity.Fullname))
|
||||||
|
throw new ArgumentException("Debe ingresar el nombre completo del profesional.", nameof(entity.Fullname));
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(entity.DocumentNumber))
|
||||||
|
throw new ArgumentException("Debe ingresar un número de documento.", nameof(entity.DocumentNumber));
|
||||||
|
|
||||||
|
return await _repository.CreateAsync(entity);
|
||||||
|
}
|
||||||
|
public async Task<bool> UpdateAsync(EProfessional entity)
|
||||||
|
{
|
||||||
|
if (entity is null)
|
||||||
|
throw new ArgumentNullException(nameof(entity), "El profesional no puede ser nulo.");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(entity.Fullname))
|
||||||
|
throw new ArgumentException("Debe ingresar el nombre completo del profesional.", nameof(entity.Fullname));
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(entity.DocumentNumber))
|
||||||
|
throw new ArgumentException("Debe ingresar un número de documento o matricula.", nameof(entity.DocumentNumber));
|
||||||
|
|
||||||
|
return await _repository.UpdateAsync(entity);
|
||||||
|
}
|
||||||
|
public async Task<PagedResult<EProfessional>> SearchAsync(
|
||||||
|
string? fullname, string? document, string? type,
|
||||||
|
int page = 1, int pageSize = 50)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _repository.SearchAsync(fullname, document, type, page, pageSize);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var method = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
throw new Exception($"{method} Message: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<byte[]> ExportFilteredProfessionalsToExcelAsync(ProfessionalSearchParams searchParams)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Realiza la búsqueda de clientes con los parámetros proporcionados
|
||||||
|
var searchResult = await SearchAsync(
|
||||||
|
searchParams.Fullname,
|
||||||
|
searchParams.Document,
|
||||||
|
searchParams.Type,
|
||||||
|
searchParams.Page,
|
||||||
|
searchParams.PageSize
|
||||||
|
);
|
||||||
|
|
||||||
|
if (searchResult?.Items is null || !searchResult.Items.Any())
|
||||||
|
throw new Exception("No se encontraron profesionales para exportar.");
|
||||||
|
|
||||||
|
var stream = new XLSXExportBase();
|
||||||
|
var professionalsData = searchResult.Items.Select(p => new
|
||||||
|
{
|
||||||
|
p.Id,
|
||||||
|
p.Fullname,
|
||||||
|
p.DocumenttypeName,
|
||||||
|
p.DocumentNumber,
|
||||||
|
Tipo = p.Type,
|
||||||
|
Especialidad = p.Specialty?.Name,
|
||||||
|
p.Email,
|
||||||
|
Teléfono1 = p.Phone1,
|
||||||
|
Teléfono2 = p.Phone2,
|
||||||
|
Dirección = p.Address,
|
||||||
|
Ciudad = p.City,
|
||||||
|
Provincia = p.Province,
|
||||||
|
CódigoPostal = p.Postalcode,
|
||||||
|
Matrícula = p.License,
|
||||||
|
p.Active,
|
||||||
|
FechaAlta = p.Createdat.ToString("dd/MM/yyyy")
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
return stream.ExportExcel(professionalsData);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var method = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
throw new Exception($"{method} Message: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<bool> DeleteAsync(int id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _repository.DeleteAsync(id);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var method = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
throw new Exception($"{method} Message: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
44
Core/Services/ProfessionalSpecialtyService.cs
Normal file
44
Core/Services/ProfessionalSpecialtyService.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using Core.Interfaces;
|
||||||
|
using Domain.Entities;
|
||||||
|
using Models.Interfaces;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Core.Services
|
||||||
|
{
|
||||||
|
public class ProfessionalSpecialtyService : IProfessionalSpecialtyDom
|
||||||
|
{
|
||||||
|
#region Declaraciones y Constructor
|
||||||
|
private readonly IPhSProfessionalSpecialtyRepository _repository;
|
||||||
|
public ProfessionalSpecialtyService(IPhSProfessionalSpecialtyRepository repository)
|
||||||
|
{
|
||||||
|
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region Metodos de clase
|
||||||
|
public async Task<IEnumerable<EProfessionalSpecialty>> GetAllAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _repository.GetAllAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
throw new Exception($"{methodName} Message: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<EProfessionalSpecialty?> GetByNameAsync(string name)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _repository.GetByNameAsync(name);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
throw new Exception($"{methodName} Message: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
30
Domain/Entities/EProfessional.cs
Normal file
30
Domain/Entities/EProfessional.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Domain.Entities
|
||||||
|
{
|
||||||
|
public class EProfessional
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
[Required(ErrorMessage = "Debe ingresar el nombre del profesional.")]
|
||||||
|
public string Fullname { get; set; } = null!;
|
||||||
|
public string? Address { get; set; }
|
||||||
|
public string? City { get; set; }
|
||||||
|
[Required(ErrorMessage = "Debe seleccionar una provincia.")]
|
||||||
|
public string? Province { get; set; }
|
||||||
|
public string? Postalcode { get; set; }
|
||||||
|
public string? Phone1 { get; set; }
|
||||||
|
public string? Phone2 { get; set; }
|
||||||
|
public string? License { get; set; }
|
||||||
|
public string? Email { get; set; }
|
||||||
|
public string? DocumenttypeName { get; set; }
|
||||||
|
public string? DocumentNumber { get; set; }
|
||||||
|
[Required(ErrorMessage = "Debe seleccionar un tipo de documento.")]
|
||||||
|
public string? Type { get; set; }
|
||||||
|
[Required(ErrorMessage = "Debe seleccionar la especialidad del profesional.")]
|
||||||
|
public int? SpecialtyId { get; set; }
|
||||||
|
public bool Active { get; set; } = true;
|
||||||
|
public DateTime Createdat { get; set; }
|
||||||
|
public virtual EProfessionalSpecialty? Specialty { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
9
Domain/Entities/EProfessionalSpecialty.cs
Normal file
9
Domain/Entities/EProfessionalSpecialty.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Domain.Entities
|
||||||
|
{
|
||||||
|
public class EProfessionalSpecialty
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
public bool Active { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Domain/Generics/ProfessionalSearchParams.cs
Normal file
9
Domain/Generics/ProfessionalSearchParams.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Domain.Generics
|
||||||
|
{
|
||||||
|
public class ProfessionalSearchParams : PagedRequest
|
||||||
|
{
|
||||||
|
public string? Fullname { get; set; }
|
||||||
|
public string? Document{ get; set; }
|
||||||
|
public string? Type { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@
|
|||||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.2</NuGetToolVersion>
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.1</NuGetToolVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
||||||
|
|||||||
17
Models/Interfaces/IPhSProfessionalRepository.cs
Normal file
17
Models/Interfaces/IPhSProfessionalRepository.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
using Domain.Entities;
|
||||||
|
using Domain.Generics;
|
||||||
|
|
||||||
|
namespace Models.Interfaces
|
||||||
|
{
|
||||||
|
public interface IPhSProfessionalRepository
|
||||||
|
{
|
||||||
|
Task<EProfessional> CreateAsync(EProfessional entity);
|
||||||
|
Task<bool> DeleteAsync(int id);
|
||||||
|
Task<PagedResult<EProfessional>> GetAllAsync(int page = 1, int pageSize = 50);
|
||||||
|
Task<EProfessional?> GetByIdAsync(int id);
|
||||||
|
Task<PagedResult<EProfessional>> SearchAsync(string? fullname, string? document, string? type,
|
||||||
|
int page = 1, int pageSize = 50);
|
||||||
|
Task<bool> UpdateAsync(EProfessional entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Models/Interfaces/IPhSProfessionalSpecialtyRepository.cs
Normal file
10
Models/Interfaces/IPhSProfessionalSpecialtyRepository.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using Domain.Entities;
|
||||||
|
|
||||||
|
namespace Models.Interfaces
|
||||||
|
{
|
||||||
|
public interface IPhSProfessionalSpecialtyRepository
|
||||||
|
{
|
||||||
|
Task<IEnumerable<EProfessionalSpecialty>> GetAllAsync();
|
||||||
|
Task<EProfessionalSpecialty?> GetByNameAsync(string name);
|
||||||
|
}
|
||||||
|
}
|
||||||
41
Models/Models/PhSProfessional.cs
Normal file
41
Models/Models/PhSProfessional.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Models.Models;
|
||||||
|
|
||||||
|
public partial class PhSProfessional
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public string Fullname { get; set; } = null!;
|
||||||
|
|
||||||
|
public string? Address { get; set; }
|
||||||
|
|
||||||
|
public string? City { get; set; }
|
||||||
|
|
||||||
|
public string? Province { get; set; }
|
||||||
|
|
||||||
|
public string? Postalcode { get; set; }
|
||||||
|
|
||||||
|
public string? Phone1 { get; set; }
|
||||||
|
|
||||||
|
public string? Phone2 { get; set; }
|
||||||
|
|
||||||
|
public string? License { get; set; }
|
||||||
|
|
||||||
|
public string? Email { get; set; }
|
||||||
|
|
||||||
|
public string? DocumenttypeName { get; set; }
|
||||||
|
|
||||||
|
public string? DocumentNumber { get; set; }
|
||||||
|
|
||||||
|
public string? Type { get; set; }
|
||||||
|
|
||||||
|
public int? SpecialtyId { get; set; }
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
|
||||||
|
public DateTime Createdat { get; set; }
|
||||||
|
|
||||||
|
public virtual PhSProfessionalSpecialty? Specialty { get; set; }
|
||||||
|
}
|
||||||
15
Models/Models/PhSProfessionalSpecialty.cs
Normal file
15
Models/Models/PhSProfessionalSpecialty.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Models.Models;
|
||||||
|
|
||||||
|
public partial class PhSProfessionalSpecialty
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<PhSProfessional> PhSProfessionals { get; set; } = new List<PhSProfessional>();
|
||||||
|
}
|
||||||
@ -39,6 +39,10 @@ public partial class PhronCareOperationsHubContext : DbContext
|
|||||||
|
|
||||||
public virtual DbSet<PhSProductCategory> PhSProductCategories { get; set; }
|
public virtual DbSet<PhSProductCategory> PhSProductCategories { get; set; }
|
||||||
|
|
||||||
|
public virtual DbSet<PhSProfessional> PhSProfessionals { get; set; }
|
||||||
|
|
||||||
|
public virtual DbSet<PhSProfessionalSpecialty> PhSProfessionalSpecialties { get; set; }
|
||||||
|
|
||||||
public virtual DbSet<PhSQuoteDetail> PhSQuoteDetails { get; set; }
|
public virtual DbSet<PhSQuoteDetail> PhSQuoteDetails { get; set; }
|
||||||
|
|
||||||
public virtual DbSet<PhSQuoteHeader> PhSQuoteHeaders { get; set; }
|
public virtual DbSet<PhSQuoteHeader> PhSQuoteHeaders { get; set; }
|
||||||
@ -52,7 +56,7 @@ public partial class PhronCareOperationsHubContext : DbContext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
//=> optionsBuilder.UseSqlServer("data source=srv01.saludlab.com.ar,39458;initial catalog=phronCare_OperationsHub;User ID=sa;Password=HS|s[~xxQzTo/n>9jO;encrypt=False;trustServerCertificate=True;MultipleActiveResultSets=True");
|
//optionsBuilder.UseSqlServer("data source=srv01.saludlab.com.ar,39458;initial catalog=phronCare_OperationsHub;User ID=sa;Password=HS|s[~xxQzTo/n>9jO;encrypt=False;trustServerCertificate=True;MultipleActiveResultSets=True");
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
@ -410,6 +414,78 @@ public partial class PhronCareOperationsHubContext : DbContext
|
|||||||
.HasColumnName("name");
|
.HasColumnName("name");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<PhSProfessional>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id).HasName("PK__PhS_Prof__3213E83F86B052AD");
|
||||||
|
|
||||||
|
entity.ToTable("PhS_Professionals");
|
||||||
|
|
||||||
|
entity.Property(e => e.Id).HasColumnName("id");
|
||||||
|
entity.Property(e => e.Active)
|
||||||
|
.HasDefaultValue(true)
|
||||||
|
.HasColumnName("active");
|
||||||
|
entity.Property(e => e.Address)
|
||||||
|
.HasMaxLength(250)
|
||||||
|
.HasColumnName("address");
|
||||||
|
entity.Property(e => e.City)
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnName("city");
|
||||||
|
entity.Property(e => e.Createdat)
|
||||||
|
.HasDefaultValueSql("(getdate())")
|
||||||
|
.HasColumnType("datetime")
|
||||||
|
.HasColumnName("createdat");
|
||||||
|
entity.Property(e => e.DocumentNumber)
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnName("document_number");
|
||||||
|
entity.Property(e => e.DocumenttypeName)
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnName("documenttype_name");
|
||||||
|
entity.Property(e => e.Email)
|
||||||
|
.HasMaxLength(150)
|
||||||
|
.HasColumnName("email");
|
||||||
|
entity.Property(e => e.Fullname)
|
||||||
|
.HasMaxLength(200)
|
||||||
|
.HasColumnName("fullname");
|
||||||
|
entity.Property(e => e.License)
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnName("license");
|
||||||
|
entity.Property(e => e.Phone1)
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnName("phone1");
|
||||||
|
entity.Property(e => e.Phone2)
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnName("phone2");
|
||||||
|
entity.Property(e => e.Postalcode)
|
||||||
|
.HasMaxLength(20)
|
||||||
|
.HasColumnName("postalcode");
|
||||||
|
entity.Property(e => e.Province)
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnName("province");
|
||||||
|
entity.Property(e => e.SpecialtyId).HasColumnName("specialty_id");
|
||||||
|
entity.Property(e => e.Type)
|
||||||
|
.HasMaxLength(25)
|
||||||
|
.HasColumnName("type");
|
||||||
|
|
||||||
|
entity.HasOne(d => d.Specialty).WithMany(p => p.PhSProfessionals)
|
||||||
|
.HasForeignKey(d => d.SpecialtyId)
|
||||||
|
.HasConstraintName("FK_Professionals_Specialty");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<PhSProfessionalSpecialty>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id).HasName("PK__PhS_Prof__3213E83F14C8B007");
|
||||||
|
|
||||||
|
entity.ToTable("PhS_ProfessionalSpecialties");
|
||||||
|
|
||||||
|
entity.Property(e => e.Id).HasColumnName("id");
|
||||||
|
entity.Property(e => e.Active)
|
||||||
|
.HasDefaultValue(true)
|
||||||
|
.HasColumnName("active");
|
||||||
|
entity.Property(e => e.Name)
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnName("name");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity<PhSQuoteDetail>(entity =>
|
modelBuilder.Entity<PhSQuoteDetail>(entity =>
|
||||||
{
|
{
|
||||||
entity.ToTable("PhS_QuoteDetails");
|
entity.ToTable("PhS_QuoteDetails");
|
||||||
|
|||||||
124
Models/Repositories/PhSProfessionalRepository.cs
Normal file
124
Models/Repositories/PhSProfessionalRepository.cs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
using Domain.Entities;
|
||||||
|
using Domain.Generics;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Models.Helpers;
|
||||||
|
using Models.Interfaces;
|
||||||
|
using Models.Models;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
|
||||||
|
namespace Models.Repositories
|
||||||
|
{
|
||||||
|
public class PhSProfessionalRepository(PhronCareOperationsHubContext context) : IPhSProfessionalRepository
|
||||||
|
{
|
||||||
|
#region Declaraciones y Constructor
|
||||||
|
private readonly PhronCareOperationsHubContext _context = context;
|
||||||
|
#endregion
|
||||||
|
#region Métodos de clase
|
||||||
|
public async Task<PagedResult<EProfessional>> GetAllAsync(int page = 1, int pageSize = 50)
|
||||||
|
{
|
||||||
|
var query = _context.PhSProfessionals
|
||||||
|
.Include(p => p.Specialty)
|
||||||
|
.AsQueryable();
|
||||||
|
|
||||||
|
var pagedEntities = await query.ToPagedResultAsync(page, pageSize);
|
||||||
|
|
||||||
|
return new PagedResult<EProfessional>
|
||||||
|
{
|
||||||
|
Items = pagedEntities.Items.Select(EntityMapper.MapEntity<PhSProfessional, EProfessional>),
|
||||||
|
TotalItems = pagedEntities.TotalItems,
|
||||||
|
Page = pagedEntities.Page,
|
||||||
|
PageSize = pagedEntities.PageSize
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public async Task<EProfessional?> GetByIdAsync(int id)
|
||||||
|
{
|
||||||
|
var professional = await _context.PhSProfessionals
|
||||||
|
.Include(p => p.Specialty)
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == id);
|
||||||
|
|
||||||
|
return professional != null ? EntityMapper.MapEntity<PhSProfessional, EProfessional>(professional) : null;
|
||||||
|
}
|
||||||
|
public async Task<PagedResult<EProfessional>> SearchAsync(string? fullname, string? document, string? type,
|
||||||
|
int page = 1, int pageSize = 50)
|
||||||
|
{
|
||||||
|
var query = _context.PhSProfessionals
|
||||||
|
.Include(p => p.Specialty)
|
||||||
|
.AsQueryable();
|
||||||
|
if (!string.IsNullOrWhiteSpace(fullname)) query = query.Where(c => c.Fullname.ToLower().Contains(fullname.ToLower()));
|
||||||
|
if (!string.IsNullOrWhiteSpace(document) && document != "?")
|
||||||
|
{
|
||||||
|
query = query.Where(p =>
|
||||||
|
EF.Functions.Like(p.DocumentNumber ?? "", $"%{document}%") ||
|
||||||
|
EF.Functions.Like(p.License ?? "", $"%{document}%"));
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(type)) query = query.Where(c => c.Type.ToLower().Contains(type.ToLower()));
|
||||||
|
|
||||||
|
var pagedEntities = await query.ToPagedResultAsync(page, pageSize);
|
||||||
|
|
||||||
|
return new PagedResult<EProfessional>
|
||||||
|
{
|
||||||
|
Items = pagedEntities.Items.Select(EntityMapper.MapEntity<PhSProfessional, EProfessional>),
|
||||||
|
TotalItems = pagedEntities.TotalItems,
|
||||||
|
Page = pagedEntities.Page,
|
||||||
|
PageSize = pagedEntities.PageSize
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public async Task<EProfessional> CreateAsync(EProfessional entity)
|
||||||
|
{
|
||||||
|
if (entity == null)
|
||||||
|
throw new ArgumentNullException(nameof(entity), "El profesional no puede ser nulo.");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dbEntity = EntityMapper.MapEntity<EProfessional, PhSProfessional>(entity);
|
||||||
|
await _context.PhSProfessionals.AddAsync(dbEntity);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return EntityMapper.MapEntity<PhSProfessional, EProfessional>(dbEntity);
|
||||||
|
}
|
||||||
|
catch (DbUpdateException dbEx)
|
||||||
|
{
|
||||||
|
throw new Exception("Error al guardar el profesional en la base de datos.", dbEx);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception("Error inesperado al crear el profesional: " + ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<bool> UpdateAsync(EProfessional entity)
|
||||||
|
{
|
||||||
|
if (entity == null)
|
||||||
|
throw new ArgumentNullException(nameof(entity));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var existing = await _context.PhSProfessionals
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == entity.Id);
|
||||||
|
|
||||||
|
if (existing == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
EntityMapper.MapEntityToExisting(entity, existing);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public async Task<bool> DeleteAsync(int id)
|
||||||
|
{
|
||||||
|
var entity = await _context.PhSProfessionals.FindAsync(id);
|
||||||
|
if (entity == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_context.PhSProfessionals.Remove(entity);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Models/Repositories/PhSProfessionalSpecialtyRepository.cs
Normal file
28
Models/Repositories/PhSProfessionalSpecialtyRepository.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using Domain.Entities;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Models.Helpers;
|
||||||
|
using Models.Interfaces;
|
||||||
|
using Models.Models;
|
||||||
|
|
||||||
|
namespace Models.Repositories
|
||||||
|
{
|
||||||
|
public class PhSProfessionalSpecialtyRepository(PhronCareOperationsHubContext context) : IPhSProfessionalSpecialtyRepository
|
||||||
|
{
|
||||||
|
#region Declaraciones y Constructor
|
||||||
|
private readonly PhronCareOperationsHubContext _context = context;
|
||||||
|
#endregion
|
||||||
|
#region Metodos de clase
|
||||||
|
public async Task<IEnumerable<EProfessionalSpecialty>> GetAllAsync()
|
||||||
|
{
|
||||||
|
var specialties = await _context.PhSProfessionalSpecialties.ToListAsync();
|
||||||
|
return specialties.Select(EntityMapper.MapEntity<PhSProfessionalSpecialty, EProfessionalSpecialty>);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<EProfessionalSpecialty?> GetByNameAsync(string name)
|
||||||
|
{
|
||||||
|
var professionalSpecialty = await _context.PhSProfessionalSpecialties.FirstOrDefaultAsync(a => a.Name.Contains(name));
|
||||||
|
return professionalSpecialty != null ? EntityMapper.MapEntity<PhSProfessionalSpecialty, EProfessionalSpecialty>(professionalSpecialty) : null;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@
|
|||||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.2</NuGetToolVersion>
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.1</NuGetToolVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
||||||
|
|||||||
137
phronCare.API/Controllers/Sales/ProfessionalController.cs
Normal file
137
phronCare.API/Controllers/Sales/ProfessionalController.cs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
using Core.Interfaces;
|
||||||
|
using Domain.Entities;
|
||||||
|
using Domain.Generics;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace phronCare.API.Controllers.Sales
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class ProfessionalController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IProfessionalDom _professionalService;
|
||||||
|
|
||||||
|
public ProfessionalController(IProfessionalDom professionalService)
|
||||||
|
{
|
||||||
|
_professionalService = professionalService ?? throw new ArgumentNullException(nameof(professionalService));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("all")]
|
||||||
|
public async Task<IActionResult> GetAll([FromQuery] int page = 1, [FromQuery] int pageSize = 50)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _professionalService.GetAllAsync(page, pageSize);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("search")]
|
||||||
|
public async Task<IActionResult> Search(
|
||||||
|
[FromQuery] string? fullname,
|
||||||
|
[FromQuery] string? document,
|
||||||
|
[FromQuery] string? type,
|
||||||
|
[FromQuery] int page = 1,
|
||||||
|
[FromQuery] int pageSize = 50)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _professionalService.SearchAsync(fullname, document, type, page, pageSize);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet("{id:int}")]
|
||||||
|
public async Task<ActionResult<EProfessional>> GetById(int id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var professional = await _professionalService.GetByIdAsync(id);
|
||||||
|
if (professional == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return Ok(professional);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return StatusCode(500, $"Error: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("create")]
|
||||||
|
public async Task<IActionResult> Create([FromBody] EProfessional professional)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (professional == null)
|
||||||
|
return BadRequest("El profesional no puede ser nulo.");
|
||||||
|
|
||||||
|
var result = await _professionalService.CreateAsync(professional);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (ArgumentNullException ex)
|
||||||
|
{
|
||||||
|
return BadRequest($"Validación fallida: {ex.Message}");
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
return BadRequest($"Error de negocio: {ex.Message}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("update")]
|
||||||
|
public async Task<IActionResult> Update([FromBody] EProfessional professional)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (professional == null || professional.Id <= 0)
|
||||||
|
return BadRequest("El profesional es inválido o no tiene un ID válido.");
|
||||||
|
|
||||||
|
var success = await _professionalService.UpdateAsync(professional);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
return NotFound($"No se encontró un profesional con ID {professional.Id}.");
|
||||||
|
|
||||||
|
return Ok("Profesional actualizado correctamente.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("exportfiltered")]
|
||||||
|
public async Task<IActionResult> ExportFiltered([FromBody] ProfessionalSearchParams searchParams)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var file = await _professionalService.ExportFilteredProfessionalsToExcelAsync(searchParams);
|
||||||
|
return File(file,
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
"Profesionales.xlsx");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return BadRequest(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
using Core.Interfaces;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace phronCare.API.Controllers.Sales
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class ProfessionalSpecialtyController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IProfessionalSpecialtyDom _professionalSpecialtyService;
|
||||||
|
public ProfessionalSpecialtyController(IProfessionalSpecialtyDom professionalSpecialtyService)
|
||||||
|
{
|
||||||
|
_professionalSpecialtyService = professionalSpecialtyService ?? throw new ArgumentNullException(nameof(professionalSpecialtyService));
|
||||||
|
}
|
||||||
|
[HttpGet("GetAll")]
|
||||||
|
public async Task<IActionResult> GetAll()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _professionalSpecialtyService.GetAllAsync();
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return BadRequest(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[HttpGet("GetByName/{name}")]
|
||||||
|
public async Task<IActionResult> GetByName(string name)
|
||||||
|
{
|
||||||
|
var result = await _professionalSpecialtyService.GetByNameAsync(name);
|
||||||
|
if (result == null)
|
||||||
|
return NotFound($"No se encontró un tipo de cuenta con el nombre '{name}'.");
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -62,6 +62,12 @@ builder.Services.AddScoped<IPhSBusinessUnitRepository, PhSBusinessUnitRepository
|
|||||||
builder.Services.AddScoped<IPatientDom, PatientService>();
|
builder.Services.AddScoped<IPatientDom, PatientService>();
|
||||||
builder.Services.AddScoped<IPhSPatientRepository, PhSPatientRepository>();
|
builder.Services.AddScoped<IPhSPatientRepository, PhSPatientRepository>();
|
||||||
|
|
||||||
|
builder.Services.AddScoped<IProfessionalSpecialtyDom, ProfessionalSpecialtyService>();
|
||||||
|
builder.Services.AddScoped<IPhSProfessionalSpecialtyRepository, PhSProfessionalSpecialtyRepository>();
|
||||||
|
|
||||||
|
builder.Services.AddScoped<IProfessionalDom, ProfessionalService>();
|
||||||
|
builder.Services.AddScoped<IPhSProfessionalRepository, PhSProfessionalRepository>();
|
||||||
|
|
||||||
builder.Services.AddScoped<IInstitutionDom, InstitutionService>();
|
builder.Services.AddScoped<IInstitutionDom, InstitutionService>();
|
||||||
builder.Services.AddScoped<IPhSInstitutionRepository, PhSInstitutionRepository>();
|
builder.Services.AddScoped<IPhSInstitutionRepository, PhSInstitutionRepository>();
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -1049,6 +1049,163 @@
|
|||||||
],
|
],
|
||||||
"ReturnTypes": []
|
"ReturnTypes": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ContainingType": "phronCare.API.Controllers.Sales.ProfessionalController",
|
||||||
|
"Method": "GetById",
|
||||||
|
"RelativePath": "api/Professional/{id}",
|
||||||
|
"HttpMethod": "GET",
|
||||||
|
"IsController": true,
|
||||||
|
"Order": 0,
|
||||||
|
"Parameters": [
|
||||||
|
{
|
||||||
|
"Name": "id",
|
||||||
|
"Type": "System.Int32",
|
||||||
|
"IsRequired": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ReturnTypes": [
|
||||||
|
{
|
||||||
|
"Type": "Domain.Entities.EProfessional",
|
||||||
|
"MediaTypes": [
|
||||||
|
"text/plain",
|
||||||
|
"application/json",
|
||||||
|
"text/json"
|
||||||
|
],
|
||||||
|
"StatusCode": 200
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ContainingType": "phronCare.API.Controllers.Sales.ProfessionalController",
|
||||||
|
"Method": "GetAll",
|
||||||
|
"RelativePath": "api/Professional/all",
|
||||||
|
"HttpMethod": "GET",
|
||||||
|
"IsController": true,
|
||||||
|
"Order": 0,
|
||||||
|
"Parameters": [
|
||||||
|
{
|
||||||
|
"Name": "page",
|
||||||
|
"Type": "System.Int32",
|
||||||
|
"IsRequired": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "pageSize",
|
||||||
|
"Type": "System.Int32",
|
||||||
|
"IsRequired": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ReturnTypes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ContainingType": "phronCare.API.Controllers.Sales.ProfessionalController",
|
||||||
|
"Method": "Create",
|
||||||
|
"RelativePath": "api/Professional/create",
|
||||||
|
"HttpMethod": "POST",
|
||||||
|
"IsController": true,
|
||||||
|
"Order": 0,
|
||||||
|
"Parameters": [
|
||||||
|
{
|
||||||
|
"Name": "professional",
|
||||||
|
"Type": "Domain.Entities.EProfessional",
|
||||||
|
"IsRequired": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ReturnTypes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ContainingType": "phronCare.API.Controllers.Sales.ProfessionalController",
|
||||||
|
"Method": "ExportFiltered",
|
||||||
|
"RelativePath": "api/Professional/exportfiltered",
|
||||||
|
"HttpMethod": "POST",
|
||||||
|
"IsController": true,
|
||||||
|
"Order": 0,
|
||||||
|
"Parameters": [
|
||||||
|
{
|
||||||
|
"Name": "searchParams",
|
||||||
|
"Type": "Domain.Generics.ProfessionalSearchParams",
|
||||||
|
"IsRequired": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ReturnTypes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ContainingType": "phronCare.API.Controllers.Sales.ProfessionalController",
|
||||||
|
"Method": "Search",
|
||||||
|
"RelativePath": "api/Professional/search",
|
||||||
|
"HttpMethod": "GET",
|
||||||
|
"IsController": true,
|
||||||
|
"Order": 0,
|
||||||
|
"Parameters": [
|
||||||
|
{
|
||||||
|
"Name": "fullname",
|
||||||
|
"Type": "System.String",
|
||||||
|
"IsRequired": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "document",
|
||||||
|
"Type": "System.String",
|
||||||
|
"IsRequired": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "type",
|
||||||
|
"Type": "System.String",
|
||||||
|
"IsRequired": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "page",
|
||||||
|
"Type": "System.Int32",
|
||||||
|
"IsRequired": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "pageSize",
|
||||||
|
"Type": "System.Int32",
|
||||||
|
"IsRequired": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ReturnTypes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ContainingType": "phronCare.API.Controllers.Sales.ProfessionalController",
|
||||||
|
"Method": "Update",
|
||||||
|
"RelativePath": "api/Professional/update",
|
||||||
|
"HttpMethod": "PUT",
|
||||||
|
"IsController": true,
|
||||||
|
"Order": 0,
|
||||||
|
"Parameters": [
|
||||||
|
{
|
||||||
|
"Name": "professional",
|
||||||
|
"Type": "Domain.Entities.EProfessional",
|
||||||
|
"IsRequired": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ReturnTypes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ContainingType": "phronCare.API.Controllers.Sales.ProfessionalSpecialtyController",
|
||||||
|
"Method": "GetAll",
|
||||||
|
"RelativePath": "api/ProfessionalSpecialty/GetAll",
|
||||||
|
"HttpMethod": "GET",
|
||||||
|
"IsController": true,
|
||||||
|
"Order": 0,
|
||||||
|
"Parameters": [],
|
||||||
|
"ReturnTypes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ContainingType": "phronCare.API.Controllers.Sales.ProfessionalSpecialtyController",
|
||||||
|
"Method": "GetByName",
|
||||||
|
"RelativePath": "api/ProfessionalSpecialty/GetByName/{name}",
|
||||||
|
"HttpMethod": "GET",
|
||||||
|
"IsController": true,
|
||||||
|
"Order": 0,
|
||||||
|
"Parameters": [
|
||||||
|
{
|
||||||
|
"Name": "name",
|
||||||
|
"Type": "System.String",
|
||||||
|
"IsRequired": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ReturnTypes": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ContainingType": "phronCare.API.Controllers.Sales.TaxConditionController",
|
"ContainingType": "phronCare.API.Controllers.Sales.TaxConditionController",
|
||||||
"Method": "GetAll",
|
"Method": "GetAll",
|
||||||
|
|||||||
210
phronCare.UIBlazor/Pages/Sales/ProfessionalForm.razor
Normal file
210
phronCare.UIBlazor/Pages/Sales/ProfessionalForm.razor
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
@page "/sales/professionalform/"
|
||||||
|
@page "/sales/professionalform/{Id:int?}"
|
||||||
|
@using phronCare.UIBlazor.Services.Sales
|
||||||
|
@inject ProfessionalService ProfessionalService
|
||||||
|
@inject DocumentTypeService documentTypeService
|
||||||
|
@inject ProfessionalSpecialtyService specialtyService
|
||||||
|
|
||||||
|
|
||||||
|
@inject NavigationManager Navigation
|
||||||
|
@inject IToastService toastService
|
||||||
|
|
||||||
|
<EditForm Model="model" OnValidSubmit="HandleValidSubmit">
|
||||||
|
<DataAnnotationsValidator />
|
||||||
|
<ValidationSummary />
|
||||||
|
|
||||||
|
<div class="card mt-4" style="zoom:80%">
|
||||||
|
<div class="card-header d-flex justify-content-center align-items-center">
|
||||||
|
<h3 class="card-title m-0">@((model.Id == 0) ? "Nuevo Profesional" : "Editar Profesional")</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12 mb-3">
|
||||||
|
<label for="Fullname" class="form-label">Nombre Completo</label>
|
||||||
|
<InputText id="Fullname" class="form-control" @bind-Value="model.Fullname" />
|
||||||
|
<ValidationMessage For="@(() => model.Fullname)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4 mb-3">
|
||||||
|
<label for="DocumentType" class="form-label">Tipo de documento:</label>
|
||||||
|
<InputSelect id="DocumentType" @bind-Value="model.DocumenttypeName" class="form-control">
|
||||||
|
<option value="">Seleccione un tipo</option>
|
||||||
|
@foreach (var type in documentTypes)
|
||||||
|
{
|
||||||
|
<option value="@type.Code">@type.Description</option>
|
||||||
|
}
|
||||||
|
</InputSelect>
|
||||||
|
<ValidationMessage For="@(() => model.DocumenttypeName)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4 mb-3">
|
||||||
|
<label for="DocumentNumber" class="form-label">Número</label>
|
||||||
|
<InputText id="DocumentNumber" class="form-control" @bind-Value="model.DocumentNumber" />
|
||||||
|
<ValidationMessage For="@(() => model.DocumentNumber)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4 mb-3">
|
||||||
|
<label for="License" class="form-label">Matrícula</label>
|
||||||
|
<InputText id="License" class="form-control" @bind-Value="model.License" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="Phone1" class="form-label">Teléfono Principal</label>
|
||||||
|
<InputText id="Phone1" class="form-control" @bind-Value="model.Phone1" />
|
||||||
|
<ValidationMessage For="@(() => model.Phone1)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="Phone2" class="form-label">Teléfono Secundario</label>
|
||||||
|
<InputText id="Phone2" class="form-control" @bind-Value="model.Phone2" />
|
||||||
|
<ValidationMessage For="@(() => model.Phone2)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4 mb-3">
|
||||||
|
<label for="Email" class="form-label">Email</label>
|
||||||
|
<InputText id="Email" type="email" class="form-control" @bind-Value="model.Email" />
|
||||||
|
<ValidationMessage For="@(() => model.Email)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-3 mb-3">
|
||||||
|
<label for="Type" class="form-label">Tipo de Profesional</label>
|
||||||
|
<InputSelect id="Type" class="form-select" @bind-Value="model.Type">
|
||||||
|
@foreach (var option in professionalTypes)
|
||||||
|
{
|
||||||
|
<option value="@option.Value">@option.Text</option>
|
||||||
|
}
|
||||||
|
</InputSelect>
|
||||||
|
<ValidationMessage For="@(() => model.Type)" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 mb-3">
|
||||||
|
<label for="Specialtyid" class="form-label">Especialidad</label>
|
||||||
|
<InputSelect id="Specialtyid" class="form-select" @bind-Value="model.SpecialtyId">
|
||||||
|
<option value="">--- Seleccionar ---</option>
|
||||||
|
@foreach (var s in specialties)
|
||||||
|
{
|
||||||
|
<option value="@s.Id">@s.Name</option>
|
||||||
|
}
|
||||||
|
</InputSelect>
|
||||||
|
<ValidationMessage For="@(() => model.SpecialtyId)" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1 mb-3 d-flex align-items-center justify-content-start mt-4">
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<InputCheckbox id="Isactive" @bind-Value="model.Active" class="form-check-input" />
|
||||||
|
<label class="form-check-label ms-2" for="Isactive">Activo</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label for="Address" class="form-label">Dirección</label>
|
||||||
|
<InputText id="Address" class="form-control" @bind-Value="model.Address" />
|
||||||
|
<ValidationMessage For="@(() => model.Address)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-3 mb-3">
|
||||||
|
<label for="City" class="form-label">Ciudad</label>
|
||||||
|
<InputText id="City" class="form-control" @bind-Value="model.City" />
|
||||||
|
<ValidationMessage For="@(() => model.City)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-3 mb-3">
|
||||||
|
<label for="Province" class="form-label">Provincia:</label>
|
||||||
|
<InputSelect id="Province" @bind-Value="model.Province" class="form-control">
|
||||||
|
<option value="">--- Seleccionar ---</option>
|
||||||
|
@foreach (var province in provinces)
|
||||||
|
{
|
||||||
|
<option value="@province">@province</option>
|
||||||
|
}
|
||||||
|
</InputSelect>
|
||||||
|
<ValidationMessage For="@(() => model.Province)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="d-flex justify-content-end align-items-center py-3">
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary me-2">Guardar</button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancelar</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</EditForm>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public int? Id { get; set; }
|
||||||
|
|
||||||
|
private EProfessional model = new();
|
||||||
|
private List<EDocumentType> documentTypes = new();
|
||||||
|
private List<EProfessionalSpecialty> specialties = new();
|
||||||
|
|
||||||
|
private List<string> provinces = new()
|
||||||
|
{
|
||||||
|
"Buenos Aires", "CABA", "Catamarca", "Chaco", "Chubut", "Córdoba", "Corrientes",
|
||||||
|
"Entre Ríos", "Formosa", "Jujuy", "La Pampa", "La Rioja", "Mendoza", "Misiones",
|
||||||
|
"Neuquén", "Río Negro", "Salta", "San Juan", "San Luis", "Santa Cruz",
|
||||||
|
"Santa Fe", "Santiago del Estero", "Tierra del Fuego", "Tucumán"
|
||||||
|
};
|
||||||
|
private List<(string Value, string Text)> professionalTypes = new()
|
||||||
|
{
|
||||||
|
("","--- Seleccionar ---"),
|
||||||
|
("Medico", "Médico"),
|
||||||
|
("Instrumentador", "Instrumentador quirúrgico"),
|
||||||
|
("Enfermero", "Enfermero/a"),
|
||||||
|
("Tecnico", "Técnico quirúrgico")
|
||||||
|
};
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
await LoadDocumentTypes();
|
||||||
|
await LoadSpecialties();
|
||||||
|
|
||||||
|
|
||||||
|
if (Id.HasValue && Id > 0)
|
||||||
|
{
|
||||||
|
var result = await ProfessionalService.GetById(Id.Value);
|
||||||
|
if (result != null)
|
||||||
|
model = result;
|
||||||
|
else
|
||||||
|
toastService.ShowError("No se pudo cargar el profesional.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async Task LoadDocumentTypes()
|
||||||
|
{
|
||||||
|
documentTypes = await documentTypeService.GetAllAsync();
|
||||||
|
}
|
||||||
|
private async Task LoadSpecialties()
|
||||||
|
{
|
||||||
|
specialties = await specialtyService.GetAllAsync();
|
||||||
|
}
|
||||||
|
private async Task HandleValidSubmit()
|
||||||
|
{
|
||||||
|
var result = model.Id == 0
|
||||||
|
? await ProfessionalService.CreateAsync(model)
|
||||||
|
: await ProfessionalService.UpdateAsync(model);
|
||||||
|
|
||||||
|
if (result.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
toastService.ShowSuccess("Profesional guardado correctamente.");
|
||||||
|
Navigation.NavigateTo("/sales/professionals");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var error = await result.Content.ReadAsStringAsync();
|
||||||
|
toastService.ShowError($"Error: {error}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel()
|
||||||
|
{
|
||||||
|
Navigation.NavigateTo("/sales/professionals");
|
||||||
|
}
|
||||||
|
}
|
||||||
210
phronCare.UIBlazor/Pages/Sales/Professionals.razor
Normal file
210
phronCare.UIBlazor/Pages/Sales/Professionals.razor
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
@page "/sales/professionals"
|
||||||
|
@using phronCare.UIBlazor.Services.Sales
|
||||||
|
@using phronCare.UIBlazor.Data
|
||||||
|
@using Domain.Entities
|
||||||
|
@using Domain.Generics
|
||||||
|
@inject IToastService toastService
|
||||||
|
@inject NavigationManager Navigation
|
||||||
|
@inject ProfessionalService professionalService
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-center align-items-center" style="zoom:80%;">
|
||||||
|
<h3 class="card-title m-0">Búsqueda de profesionales</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body" style="zoom:80%;">
|
||||||
|
<div class="mb-4 space-y-2">
|
||||||
|
<input @bind="SearchParams.Fullname" placeholder="Nombre y apellido" class="border rounded p-1 w-full" />
|
||||||
|
<input @bind="SearchParams.Document" placeholder="Documento o Matricula" class="border rounded p-1 w-full" />
|
||||||
|
<input @bind="SearchParams.Type" placeholder="Tipo de profesional" class="border rounded p-1 w-full" />
|
||||||
|
<button class="btn btn-primary rounded-pill" @onclick="BuscarProfesionales">
|
||||||
|
<i class="fas fa-binoculars me-1"></i> Buscar
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-success rounded-pill" @onclick="NuevoProfesional">
|
||||||
|
<i class="fas fa-plus me-1"></i> Nuevo
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-success rounded-pill" @onclick="ExportarExcel">
|
||||||
|
<i class="fas fa-file-excel me-1"></i> Excel
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-secondary rounded-pill" @onclick="Cancel">
|
||||||
|
<i class="fas fa-arrow-left me-1"></i> Volver
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div>
|
||||||
|
@if (TablaProfesionales != null && TablaProfesionales.Any())
|
||||||
|
{
|
||||||
|
<PhTable Columns="TableColumns"
|
||||||
|
Data="TablaProfesionales"
|
||||||
|
SelectionField="Id"
|
||||||
|
RowsPerPage=SearchParams.PageSize
|
||||||
|
RenderButtons="true" Buttons="botones"
|
||||||
|
ShowPageButtons="false"
|
||||||
|
ShowQuickSearch="false"
|
||||||
|
RenderSelect="false" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<p>No hay resultados.</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer d-flex justify-content-center align-items-center" style="zoom:80%;">
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
<button class="btn btn-secondary rounded-pill" @onclick="PrimeraPagina" disabled="@(SearchParams.Page == 1)">
|
||||||
|
<i class="fas fa-angle-double-left me-1"></i> Primera
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-secondary rounded-pill" @onclick="AnteriorPagina" disabled="@(!PuedeRetroceder)">
|
||||||
|
<i class="fas fa-chevron-left me-1"></i> Anterior
|
||||||
|
</button>
|
||||||
|
<span class="mx-2">
|
||||||
|
Página <strong>@SearchParams.Page</strong> de <strong>@TotalPaginas</strong>
|
||||||
|
</span>
|
||||||
|
<button class="btn btn-secondary rounded-pill" @onclick="SiguientePagina" disabled="@(!PuedeAvanzar)">
|
||||||
|
Siguiente <i class="fas fa-chevron-right ms-1"></i>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-secondary rounded-pill" @onclick="UltimaPagina" disabled="@(SearchParams.Page == TotalPaginas)">
|
||||||
|
Última <i class="fas fa-angle-double-right ms-1"></i>
|
||||||
|
</button>
|
||||||
|
<div class="d-flex align-items-center ms-3">
|
||||||
|
<input type="number" class="form-control form-control-sm rounded" style="width: 80px;" min="1" max="@TotalPaginas" @bind="PaginaDeseada" />
|
||||||
|
<button class="btn btn-outline-primary btn-sm ms-2 rounded-pill" @onclick="IrAPagina">
|
||||||
|
<i class="fas fa-arrow-right-to-bracket me-1"></i> Ir
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private ProfessionalSearchParams SearchParams = new();
|
||||||
|
private PagedResult<EProfessional>? PagedResult;
|
||||||
|
private List<Dictionary<string, object>> TablaProfesionales = new();
|
||||||
|
private List<string> TableColumns = new()
|
||||||
|
{
|
||||||
|
"Id", "Nombre", "Tipo Documento", "N° Documento", "Tipo", "Especialidad",
|
||||||
|
"Email", "Teléfono 1", "Teléfono 2", "Matrícula", "Activo"
|
||||||
|
};
|
||||||
|
private int PaginaDeseada = 1;
|
||||||
|
private List<PhTable.ButtonOptions> botones = new();
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
botones = new List<PhTable.ButtonOptions>
|
||||||
|
{
|
||||||
|
new PhTable.ButtonOptions
|
||||||
|
{
|
||||||
|
Caption = "Editar",
|
||||||
|
ElementClass = "btn btn-primary btn-sm",
|
||||||
|
UrlAction = "/sales/professionals/edit/",
|
||||||
|
OnClickAction = async (id) =>
|
||||||
|
{
|
||||||
|
if (int.TryParse(id, out var profId))
|
||||||
|
{
|
||||||
|
Navigation.NavigateTo($"/sales/professionalform/{profId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task BuscarProfesionales()
|
||||||
|
{
|
||||||
|
await CargarProfesionales();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CargarProfesionales()
|
||||||
|
{
|
||||||
|
PagedResult = await professionalService.SearchAsync(SearchParams);
|
||||||
|
if (PagedResult?.Items is not null)
|
||||||
|
{
|
||||||
|
TablaProfesionales = PagedResult.Items.Select(p => new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "Id", p.Id },
|
||||||
|
{ "Nombre", p.Fullname ?? string.Empty },
|
||||||
|
{ "Tipo Documento", p.DocumenttypeName ?? string.Empty },
|
||||||
|
{ "N° Documento", p.DocumentNumber ?? string.Empty },
|
||||||
|
{ "Tipo", p.Type ?? string.Empty },
|
||||||
|
{ "Especialidad", p.Specialty?.Name ?? string.Empty },
|
||||||
|
{ "Email", p.Email ?? string.Empty },
|
||||||
|
{ "Teléfono 1", p.Phone1 ?? string.Empty },
|
||||||
|
{ "Teléfono 2", p.Phone2 ?? string.Empty },
|
||||||
|
{ "Matrícula", p.License ?? string.Empty },
|
||||||
|
{ "Activo", p.Active ? "Sí" : "No" },
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExportarExcel()
|
||||||
|
{
|
||||||
|
var searchParams = new ProfessionalSearchParams
|
||||||
|
{
|
||||||
|
Fullname = SearchParams.Fullname,
|
||||||
|
Document = SearchParams.Document,
|
||||||
|
Type = SearchParams.Type,
|
||||||
|
Page = 1,
|
||||||
|
PageSize = int.MaxValue
|
||||||
|
};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await professionalService.ExportFilteredAsync(searchParams);
|
||||||
|
toastService.ShowSuccess("Exportación completada exitosamente.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
toastService.ShowError($"{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PrimeraPagina()
|
||||||
|
{
|
||||||
|
SearchParams.Page = 1;
|
||||||
|
await BuscarProfesionales();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UltimaPagina()
|
||||||
|
{
|
||||||
|
SearchParams.Page = TotalPaginas;
|
||||||
|
await BuscarProfesionales();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task IrAPagina()
|
||||||
|
{
|
||||||
|
if (PaginaDeseada >= 1 && PaginaDeseada <= TotalPaginas)
|
||||||
|
{
|
||||||
|
SearchParams.Page = PaginaDeseada;
|
||||||
|
await BuscarProfesionales();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toastService.ShowWarning("Número de página fuera de rango.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SiguientePagina() => await CambiarPagina(1);
|
||||||
|
private async Task AnteriorPagina() => await CambiarPagina(-1);
|
||||||
|
private async Task CambiarPagina(int delta)
|
||||||
|
{
|
||||||
|
var nuevaPagina = SearchParams.Page + delta;
|
||||||
|
if (nuevaPagina >= 1 && nuevaPagina <= TotalPaginas)
|
||||||
|
{
|
||||||
|
SearchParams.Page = nuevaPagina;
|
||||||
|
await BuscarProfesionales();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int TotalPaginas => PagedResult is null ? 1 :
|
||||||
|
(int)Math.Ceiling((double)(PagedResult.TotalItems) / SearchParams.PageSize);
|
||||||
|
|
||||||
|
private bool PuedeRetroceder => PagedResult != null && SearchParams.Page > 1;
|
||||||
|
private bool PuedeAvanzar => PagedResult != null && SearchParams.Page < TotalPaginas;
|
||||||
|
|
||||||
|
private void NuevoProfesional()
|
||||||
|
{
|
||||||
|
Navigation.NavigateTo("/sales/professionalform/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Cancel()
|
||||||
|
{
|
||||||
|
Navigation.NavigateTo("/DashboardPanel");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -47,6 +47,8 @@ builder.Services.AddScoped<DocumentTypeService>();
|
|||||||
builder.Services.AddScoped<InstitutionService>();
|
builder.Services.AddScoped<InstitutionService>();
|
||||||
builder.Services.AddScoped<ProductService>();
|
builder.Services.AddScoped<ProductService>();
|
||||||
builder.Services.AddScoped<BusinessUnitService>();
|
builder.Services.AddScoped<BusinessUnitService>();
|
||||||
|
builder.Services.AddScoped<ProfessionalService>();
|
||||||
|
builder.Services.AddScoped<ProfessionalSpecialtyService>();
|
||||||
builder.Services.AddScoped<ProductCategoryService>();
|
builder.Services.AddScoped<ProductCategoryService>();
|
||||||
#endregion
|
#endregion
|
||||||
#region UI
|
#region UI
|
||||||
|
|||||||
72
phronCare.UIBlazor/Services/Sales/ProfessionalService.cs
Normal file
72
phronCare.UIBlazor/Services/Sales/ProfessionalService.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using Domain.Entities;
|
||||||
|
using Domain.Generics;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.JSInterop;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Net.Http;
|
||||||
|
using phronCare.UIBlazor.Pages.Sales;
|
||||||
|
|
||||||
|
namespace phronCare.UIBlazor.Services.Sales
|
||||||
|
{
|
||||||
|
public class ProfessionalService
|
||||||
|
{
|
||||||
|
private readonly HttpClient _http;
|
||||||
|
private readonly IJSRuntime _js;
|
||||||
|
public ProfessionalService(HttpClient http, IJSRuntime js)
|
||||||
|
{
|
||||||
|
_http = http;
|
||||||
|
_js = js;
|
||||||
|
}
|
||||||
|
public async Task<PagedResult<EProfessional>?> SearchAsync(ProfessionalSearchParams searchParams)
|
||||||
|
{
|
||||||
|
var url = $"api/Professional/search?" +
|
||||||
|
$"fullname={searchParams.Fullname}&" +
|
||||||
|
$"document={searchParams.Document}&" +
|
||||||
|
$"type={searchParams.Type}&" +
|
||||||
|
$"page={searchParams.Page}&" +
|
||||||
|
$"pageSize={searchParams.PageSize}";
|
||||||
|
return await _http.GetFromJsonAsync<PagedResult<EProfessional>>(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<EProfessional?> GetById(int id)
|
||||||
|
{
|
||||||
|
return await _http.GetFromJsonAsync<EProfessional>($"/api/Professional/{id}") ;
|
||||||
|
}
|
||||||
|
public async Task<HttpResponseMessage> CreateAsync(EProfessional professional)
|
||||||
|
{
|
||||||
|
return await _http.PostAsJsonAsync("/api/Professional/Create", professional);
|
||||||
|
}
|
||||||
|
public async Task<HttpResponseMessage> UpdateAsync(EProfessional professional)
|
||||||
|
{
|
||||||
|
return await _http.PutAsJsonAsync("/api/Professional/Update", professional);
|
||||||
|
}
|
||||||
|
public async Task ExportFilteredAsync(ProfessionalSearchParams searchParams)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = new StringContent(JsonSerializer.Serialize(searchParams), Encoding.UTF8, "application/json");
|
||||||
|
var response = await _http.PostAsync("api/Professional/exportfiltered", content);
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var errorContent = await response.Content.ReadAsStringAsync();
|
||||||
|
throw new Exception(errorContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes = await response.Content.ReadAsByteArrayAsync();
|
||||||
|
var base64 = Convert.ToBase64String(bytes);
|
||||||
|
var timestamp = DateTime.Now.ToString("yyyyMMddHHmm");
|
||||||
|
var fileName = $"{timestamp}_profesionales.xlsx";
|
||||||
|
await _js.InvokeVoidAsync("saveAsFile", fileName, base64);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
|
var message = ex.Message ?? "No message provided";
|
||||||
|
throw new Exception($"{message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
using Domain.Entities;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
|
||||||
|
namespace phronCare.UIBlazor.Services.Sales
|
||||||
|
{
|
||||||
|
public class ProfessionalSpecialtyService
|
||||||
|
{
|
||||||
|
private readonly HttpClient _http;
|
||||||
|
public ProfessionalSpecialtyService(HttpClient http)
|
||||||
|
{
|
||||||
|
_http = http;
|
||||||
|
}
|
||||||
|
public async Task<List<EProfessionalSpecialty>?> GetAllAsync()
|
||||||
|
{
|
||||||
|
return await _http.GetFromJsonAsync<List<EProfessionalSpecialty>>("api/ProfessionalSpecialty/GetAll");
|
||||||
|
}
|
||||||
|
public async Task<EProfessionalSpecialty?> GetByNameAsync(string name)
|
||||||
|
{
|
||||||
|
return await _http.GetFromJsonAsync<EProfessionalSpecialty>($"api/ProfessionalSpecialty/GetByName/{Uri.EscapeDataString(name)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -81,6 +81,11 @@
|
|||||||
<li aria-hidden="true"></li> Productos
|
<li aria-hidden="true"></li> Productos
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="nav-item px-1">
|
||||||
|
<NavLink class="nav-link" href="sales/professionals/">
|
||||||
|
<li aria-hidden="true"></li> Profesionales
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
<div class="nav-item px-1">
|
<div class="nav-item px-1">
|
||||||
<NavLink class="nav-link" href="sales/institutions/">
|
<NavLink class="nav-link" href="sales/institutions/">
|
||||||
<li aria-hidden="true"></li> Instituciones
|
<li aria-hidden="true"></li> Instituciones
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user