Add Patients List Completo UI
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 5m22s
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 5m22s
This commit is contained in:
parent
8623488221
commit
4ee5a99cb1
@ -8,10 +8,13 @@ namespace Domain.Entities
|
|||||||
[Required(ErrorMessage = "Debe ingresar un nombre.")]
|
[Required(ErrorMessage = "Debe ingresar un nombre.")]
|
||||||
public string Firstname { get; set; } = null!;
|
public string Firstname { get; set; } = null!;
|
||||||
public string Lastname { get; set; } = null!;
|
public string Lastname { get; set; } = null!;
|
||||||
|
[Required(ErrorMessage = "Debe ingresar un tipo de documento.")]
|
||||||
public int? DocumenttypesId { get; set; }
|
public int? DocumenttypesId { get; set; }
|
||||||
|
[Required(ErrorMessage = "Debe ingresar un numero de documento.")]
|
||||||
public string? DocumentNumber { get; set; }
|
public string? DocumentNumber { get; set; }
|
||||||
public string? AffiliateNumber { get; set; }
|
public string? AffiliateNumber { get; set; }
|
||||||
public DateOnly? Birthdate { get; set; }
|
public DateOnly? Birthdate { get; set; }
|
||||||
|
[Required(ErrorMessage = "Debe seleccionar un genero.")]
|
||||||
public string? Gender { get; set; }
|
public string? Gender { get; set; }
|
||||||
public string? Phone { get; set; }
|
public string? Phone { get; set; }
|
||||||
public string? Email { get; set; }
|
public string? Email { get; set; }
|
||||||
|
|||||||
@ -90,7 +90,7 @@ namespace phronCare.API.Controllers.Sales
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
return BadRequest($"Error de negocio: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ namespace phronCare.API.Controllers.Sales
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
||||||
return StatusCode(500, $"{methodName} Message: {ex.Message}");
|
return StatusCode(500, $"{ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
@inject AuthenticationStateProvider authenticationStateProvider
|
@inject AuthenticationStateProvider authenticationStateProvider
|
||||||
@inject AccountTypeService accountTypeService
|
@inject AccountTypeService accountTypeService
|
||||||
@inject TaxConditionService taxConditionService
|
@inject TaxConditionService taxConditionService
|
||||||
|
@inject DocumentTypeService documentTypeService
|
||||||
|
|
||||||
<div class="card" style="zoom:80%">
|
<div class="card" style="zoom:80%">
|
||||||
<div class="card-header d-flex justify-content-center align-items-center">
|
<div class="card-header d-flex justify-content-center align-items-center">
|
||||||
@ -364,8 +365,7 @@
|
|||||||
}
|
}
|
||||||
private async Task LoadDocumentTypes()
|
private async Task LoadDocumentTypes()
|
||||||
{
|
{
|
||||||
var result = await _httpClient.GetFromJsonAsync<List<EDocumentType>>("/api/DocumentType/GetAll");
|
documentTypes = await documentTypeService.GetAllAsync();
|
||||||
documentTypes = result ?? new();
|
|
||||||
}
|
}
|
||||||
private void AddCustomerDocument()
|
private void AddCustomerDocument()
|
||||||
{
|
{
|
||||||
|
|||||||
184
phronCare.UIBlazor/Pages/Sales/PatientForm.razor
Normal file
184
phronCare.UIBlazor/Pages/Sales/PatientForm.razor
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
@page "/sales/patientform"
|
||||||
|
@page "/sales/patientform/{PatientId:int?}"
|
||||||
|
@using System.ComponentModel.DataAnnotations
|
||||||
|
@using phronCare.UIBlazor.Services.Sales
|
||||||
|
@using phronCare.UIBlazor.Pages.Shared.Modals
|
||||||
|
|
||||||
|
@inject PatientService patientService
|
||||||
|
@inject DocumentTypeService documentTypeService
|
||||||
|
@inject IToastService ToastService
|
||||||
|
@inject NavigationManager Navigation
|
||||||
|
@inject IModalService Modal
|
||||||
|
|
||||||
|
<div class="card" style="zoom:80%">
|
||||||
|
<div class="card-header d-flex justify-content-center align-items-center">
|
||||||
|
<h3 class="card-title m-0">@((PatientId.HasValue ? "Editar paciente" : "Nuevo paciente"))</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<EditForm Model="_model" OnValidSubmit="HandleValidSubmit">
|
||||||
|
<DataAnnotationsValidator />
|
||||||
|
<ValidationSummary />
|
||||||
|
|
||||||
|
<!-- Fila 1: Nombre y Apellido -->
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label for="FirstName">Nombre:</label>
|
||||||
|
<InputText id="FirstName" @bind-Value="_model.Firstname" class="form-control" />
|
||||||
|
<ValidationMessage For="@(() => _model.Firstname)" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label for="LastName">Apellido:</label>
|
||||||
|
<InputText id="LastName" @bind-Value="_model.Lastname" class="form-control" />
|
||||||
|
<ValidationMessage For="@(() => _model.Lastname)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fila 2: Tipo Doc, Nro Doc, Afiliado -->
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label for="DocumentType">Tipo de documento:</label>
|
||||||
|
<InputSelect id="DocumentType" @bind-Value="_model.DocumenttypesId" class="form-control">
|
||||||
|
<option value="">Seleccione un tipo</option>
|
||||||
|
@foreach (var type in documentTypes)
|
||||||
|
{
|
||||||
|
<option value="@type.Id">@type.Description</option>
|
||||||
|
}
|
||||||
|
</InputSelect>
|
||||||
|
<ValidationMessage For="@(() => _model.DocumenttypesId)" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label for="DocumentNumber">Número de documento:</label>
|
||||||
|
<InputText id="DocumentNumber" @bind-Value="_model.DocumentNumber" class="form-control" />
|
||||||
|
<ValidationMessage For="@(() => _model.DocumentNumber)" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label for="AffiliateNumber">Número de afiliado:</label>
|
||||||
|
<InputText id="AffiliateNumber" @bind-Value="_model.AffiliateNumber" class="form-control" />
|
||||||
|
<ValidationMessage For="@(() => _model.AffiliateNumber)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fila 3: Fecha de nacimiento, Género -->
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label for="Birthdate">Fecha de nacimiento:</label>
|
||||||
|
<InputDate id="Birthdate" @bind-Value="_model.Birthdate" class="form-control" />
|
||||||
|
<ValidationMessage For="@(() => _model.Birthdate)" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label for="Gender">Género:</label>
|
||||||
|
<InputSelect id="Gender" @bind-Value="_model.Gender" class="form-control">
|
||||||
|
<option value="">Seleccione</option>
|
||||||
|
<option value="Femenino">Femenino</option>
|
||||||
|
<option value="Masculino">Masculino</option>
|
||||||
|
<option value="Otro">Otro</option>
|
||||||
|
<option value="Prefiero no decir">Prefiero no decir</option>
|
||||||
|
</InputSelect>
|
||||||
|
<ValidationMessage For="@(() => _model.Gender)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fila 4: Teléfono, Email -->
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label for="Phone">Teléfono:</label>
|
||||||
|
<InputText id="Phone" @bind-Value="_model.Phone" class="form-control" />
|
||||||
|
<ValidationMessage For="@(() => _model.Phone)" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label for="Email">Email:</label>
|
||||||
|
<InputText id="Email" @bind-Value="_model.Email" class="form-control" />
|
||||||
|
<ValidationMessage For="@(() => _model.Email)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fila 5: Dirección -->
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<label for="Address">Dirección:</label>
|
||||||
|
<InputText id="Address" @bind-Value="_model.Address" class="form-control" />
|
||||||
|
<ValidationMessage For="@(() => _model.Address)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fila 6: Notas -->
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<label for="Notes">Notas:</label>
|
||||||
|
<InputTextArea id="Notes" @bind-Value="_model.Notes" class="form-control" rows="3" />
|
||||||
|
<ValidationMessage For="@(() => _model.Notes)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</EditForm>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="d-flex justify-content-end align-items-center py-3">
|
||||||
|
<button class="btn btn-primary me-2" type="button" @onclick="HandleValidSubmit" disabled="@isSaving"> @(isSaving ? "Guardando..." : "Guardar paciente") </button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="NavigateBack">Cancelar</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter] public int? PatientId { get; set; }
|
||||||
|
[Parameter] public string? returnUrl { get; set; } = "/sales/patients";
|
||||||
|
|
||||||
|
private EPatient _model = new();
|
||||||
|
private List<EDocumentType> documentTypes = new();
|
||||||
|
private bool isSaving = false;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
await LoadDocumentTypes();
|
||||||
|
|
||||||
|
if (PatientId.HasValue)
|
||||||
|
{
|
||||||
|
_model = await patientService.GetByIdAsync(PatientId.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async Task LoadDocumentTypes()
|
||||||
|
{
|
||||||
|
documentTypes = await documentTypeService.GetAllAsync();
|
||||||
|
}
|
||||||
|
private async Task HandleValidSubmit()
|
||||||
|
{
|
||||||
|
var parameters = new ModalParameters();
|
||||||
|
parameters.Add("Message", "¿Desea guardar los cambios del paciente?");
|
||||||
|
var modal = Modal.Show<ConfirmModal>("Confirmación", parameters);
|
||||||
|
var result = await modal.Result;
|
||||||
|
|
||||||
|
if (result.Cancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpResponseMessage response;
|
||||||
|
|
||||||
|
if (_model.Id == 0)
|
||||||
|
response = await patientService.CreateAsync(_model);
|
||||||
|
else
|
||||||
|
response = await patientService.UpdateAsync(_model);
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
ToastService.ShowSuccess("Paciente guardado correctamente.");
|
||||||
|
NavigateBack();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var error = await response.Content.ReadAsStringAsync();
|
||||||
|
ToastService.ShowError($"Error: {error}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ToastService.ShowError($"Error: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NavigateBack()
|
||||||
|
{
|
||||||
|
Navigation.NavigateTo(returnUrl ?? "/sales/patients");
|
||||||
|
}
|
||||||
|
}
|
||||||
186
phronCare.UIBlazor/Pages/Sales/Patients.razor
Normal file
186
phronCare.UIBlazor/Pages/Sales/Patients.razor
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
@page "/sales/patients"
|
||||||
|
@using phronCare.UIBlazor.Services.Sales
|
||||||
|
@using phronCare.UIBlazor.Data
|
||||||
|
@using Domain.Entities
|
||||||
|
@using Domain.Generics
|
||||||
|
@using Domain.SearchParams
|
||||||
|
@inject IToastService toastService
|
||||||
|
@inject NavigationManager Navigation
|
||||||
|
@inject PatientService patientService
|
||||||
|
|
||||||
|
<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 pacientes</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body" style="zoom:80%;">
|
||||||
|
<div class="mb-4 space-y-2">
|
||||||
|
<input @bind="SearchParams.Name" placeholder="Nombre o Apellido" class="border rounded p-1 w-full" />
|
||||||
|
<input @bind="SearchParams.Document" placeholder="Documento" class="border rounded p-1 w-full" />
|
||||||
|
<button class="btn btn-primary rounded-pill" @onclick="BuscarPacientes">
|
||||||
|
<i class="fas fa-binoculars me-1"></i> Buscar
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-success rounded-pill" @onclick="NuevoPaciente">
|
||||||
|
<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="Volver">
|
||||||
|
<i class="fas fa-arrow-left me-1"></i> Volver
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div>
|
||||||
|
@if (TablaPacientes != null && TablaPacientes.Any())
|
||||||
|
{
|
||||||
|
<PhTable Columns="TableColumns"
|
||||||
|
Data="TablaPacientes"
|
||||||
|
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 PatientSearchParams SearchParams = new();
|
||||||
|
private PagedResult<EPatient>? PagedResult;
|
||||||
|
private List<Dictionary<string, object>> TablaPacientes = new();
|
||||||
|
private List<string> TableColumns = new()
|
||||||
|
{
|
||||||
|
"Id", "Nombre", "Apellido", "Documento", "#Socio | #Afiliado", "Género", "Teléfono", "Email"
|
||||||
|
};
|
||||||
|
private int PaginaDeseada = 1;
|
||||||
|
|
||||||
|
private List<PhTable.ButtonOptions> botones;
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
botones = new List<PhTable.ButtonOptions>
|
||||||
|
{
|
||||||
|
new PhTable.ButtonOptions
|
||||||
|
{
|
||||||
|
Caption = "Editar",
|
||||||
|
ElementClass = "btn btn-primary btn-sm",
|
||||||
|
UrlAction = "/sales/patientform/",
|
||||||
|
OnClickAction = async (id) =>
|
||||||
|
{
|
||||||
|
if (int.TryParse(id, out var pacienteId))
|
||||||
|
{
|
||||||
|
Navigation.NavigateTo($"/sales/patientform/{pacienteId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task BuscarPacientes() => await CargarPacientes();
|
||||||
|
|
||||||
|
private async Task CargarPacientes()
|
||||||
|
{
|
||||||
|
PagedResult = await patientService.SearchPatientsAsync(SearchParams);
|
||||||
|
if (PagedResult?.Items is not null)
|
||||||
|
{
|
||||||
|
TablaPacientes = PagedResult.Items.Select(p => new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "Id", p.Id },
|
||||||
|
{ "Nombre", p.Firstname ?? string.Empty },
|
||||||
|
{ "Apellido", p.Lastname ?? string.Empty },
|
||||||
|
{ "Documento", $"{p.DocumenttypesId} {p.DocumentNumber}" },
|
||||||
|
{ "#Socio | #Afiliado", $"{p.AffiliateNumber}" },
|
||||||
|
{ "Género", p.Gender ?? string.Empty },
|
||||||
|
{ "Teléfono", p.Phone ?? string.Empty },
|
||||||
|
{ "Email", p.Email ?? string.Empty }
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PrimeraPagina() { SearchParams.Page = 1; await BuscarPacientes(); }
|
||||||
|
private async Task UltimaPagina() { SearchParams.Page = TotalPaginas; await BuscarPacientes(); }
|
||||||
|
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 BuscarPacientes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task IrAPagina()
|
||||||
|
{
|
||||||
|
if (PaginaDeseada >= 1 && PaginaDeseada <= TotalPaginas)
|
||||||
|
{
|
||||||
|
SearchParams.Page = PaginaDeseada;
|
||||||
|
await BuscarPacientes();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toastService.ShowWarning("Número de página fuera de rango.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExportarExcel()
|
||||||
|
{
|
||||||
|
var searchParams = new PatientSearchParams
|
||||||
|
{
|
||||||
|
Name = SearchParams.Name,
|
||||||
|
Document = SearchParams.Document,
|
||||||
|
Page = 1,
|
||||||
|
PageSize = int.MaxValue
|
||||||
|
};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await patientService.ExportFilteredAsync(searchParams);
|
||||||
|
toastService.ShowSuccess("Exportación completada exitosamente.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
toastService.ShowError($"{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NuevoPaciente() => Navigation.NavigateTo("/sales/patientform/");
|
||||||
|
private void Volver() => Navigation.NavigateTo("/DashboardPanel");
|
||||||
|
|
||||||
|
private bool PuedeRetroceder => PagedResult != null && SearchParams.Page > 1;
|
||||||
|
private bool PuedeAvanzar => PagedResult != null && SearchParams.Page < TotalPaginas;
|
||||||
|
private int TotalPaginas => PagedResult is null ? 1 :
|
||||||
|
(int)Math.Ceiling((double)(PagedResult.TotalItems) / SearchParams.PageSize);
|
||||||
|
}
|
||||||
@ -42,6 +42,8 @@ builder.Services.AddScoped<TicketsService>();
|
|||||||
builder.Services.AddScoped<CustomerService>();
|
builder.Services.AddScoped<CustomerService>();
|
||||||
builder.Services.AddScoped<TaxConditionService>();
|
builder.Services.AddScoped<TaxConditionService>();
|
||||||
builder.Services.AddScoped<AccountTypeService>();
|
builder.Services.AddScoped<AccountTypeService>();
|
||||||
|
builder.Services.AddScoped<PatientService>();
|
||||||
|
builder.Services.AddScoped<DocumentTypeService>();
|
||||||
builder.Services.AddScoped<ProductService>();
|
builder.Services.AddScoped<ProductService>();
|
||||||
builder.Services.AddScoped<BusinessUnitService>();
|
builder.Services.AddScoped<BusinessUnitService>();
|
||||||
builder.Services.AddScoped<ProductCategoryService>();
|
builder.Services.AddScoped<ProductCategoryService>();
|
||||||
|
|||||||
21
phronCare.UIBlazor/Services/Sales/DocumentTypeService.cs
Normal file
21
phronCare.UIBlazor/Services/Sales/DocumentTypeService.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using Domain.Entities;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
|
||||||
|
namespace phronCare.UIBlazor.Services.Sales
|
||||||
|
{
|
||||||
|
public class DocumentTypeService
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
|
||||||
|
public DocumentTypeService(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<EDocumentType>> GetAllAsync()
|
||||||
|
{
|
||||||
|
var result = await _httpClient.GetFromJsonAsync<List<EDocumentType>>("/api/DocumentType/GetAll");
|
||||||
|
return result ?? new List<EDocumentType>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
phronCare.UIBlazor/Services/Sales/PatientService.cs
Normal file
82
phronCare.UIBlazor/Services/Sales/PatientService.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using Domain.Entities;
|
||||||
|
using Domain.Generics;
|
||||||
|
using Domain.SearchParams;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.JSInterop;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace phronCare.UIBlazor.Services.Sales
|
||||||
|
{
|
||||||
|
public class PatientService
|
||||||
|
{
|
||||||
|
private readonly HttpClient _http;
|
||||||
|
private readonly IJSRuntime _js;
|
||||||
|
|
||||||
|
public PatientService(HttpClient http, IJSRuntime js)
|
||||||
|
{
|
||||||
|
_http = http;
|
||||||
|
_js = js;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<EPatient>> GetAllAsync()
|
||||||
|
{
|
||||||
|
var result = await _http.GetFromJsonAsync<List<EPatient>>("/api/Patient/all");
|
||||||
|
return result ?? new List<EPatient>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<EPatient> GetByIdAsync(int id)
|
||||||
|
{
|
||||||
|
var result = await _http.GetFromJsonAsync<EPatient>($"/api/Patient/{id}");
|
||||||
|
return result ?? new EPatient();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponseMessage> CreateAsync(EPatient patient)
|
||||||
|
{
|
||||||
|
return await _http.PostAsJsonAsync("/api/Patient/create", patient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponseMessage> UpdateAsync(EPatient patient)
|
||||||
|
{
|
||||||
|
return await _http.PutAsJsonAsync("/api/Patient/update", patient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PagedResult<EPatient>?> SearchPatientsAsync(PatientSearchParams searchParams)
|
||||||
|
{
|
||||||
|
var url = $"api/Patient/search?" +
|
||||||
|
$"name={searchParams.Name}&" +
|
||||||
|
$"document={searchParams.Document}&" +
|
||||||
|
$"page={searchParams.Page}&" +
|
||||||
|
$"pageSize={searchParams.PageSize}";
|
||||||
|
return await _http.GetFromJsonAsync<PagedResult<EPatient>>(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ExportFilteredAsync(PatientSearchParams searchParams)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = new StringContent(JsonSerializer.Serialize(searchParams), Encoding.UTF8, "application/json");
|
||||||
|
var response = await _http.PostAsync("api/Patient/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}_pacientes.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -60,7 +60,7 @@
|
|||||||
<span class="oi oi-briefcase" aria-hidden="true"></span>
|
<span class="oi oi-briefcase" aria-hidden="true"></span>
|
||||||
@if (!navMenuService.Minimized)
|
@if (!navMenuService.Minimized)
|
||||||
{
|
{
|
||||||
<label>Clientes</label>
|
<label>Ventas</label>
|
||||||
}
|
}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
@if (expClientes)
|
@if (expClientes)
|
||||||
@ -68,12 +68,12 @@
|
|||||||
<ul class="nav-flex-column">
|
<ul class="nav-flex-column">
|
||||||
<div class="nav-item px-1">
|
<div class="nav-item px-1">
|
||||||
<NavLink class="nav-link" href="sales/customers/">
|
<NavLink class="nav-link" href="sales/customers/">
|
||||||
<li aria-hidden="true"></li> Búsqueda
|
<li aria-hidden="true"></li> Clientes
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-item px-1">
|
<div class="nav-item px-1">
|
||||||
<NavLink class="nav-link" href="sales/customerform/">
|
<NavLink class="nav-link" href="sales/patients/">
|
||||||
<li aria-hidden="true"></li> Crear
|
<li aria-hidden="true"></li> Pacientes
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-item px-1">
|
<div class="nav-item px-1">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user