From d5722495ae29a6aaa118d9e68eba1872e5997af3 Mon Sep 17 00:00:00 2001 From: Leandro Hernan Rojas Date: Mon, 14 Apr 2025 17:50:25 -0300 Subject: [PATCH] Add Update API UI Customers CRUD --- Core/Interfaces/ICustomerDom.cs | 10 +- Core/Services/CustomerService.cs | 59 +++++-- Domain/Entities/EAccountType.cs | 14 +- Domain/Entities/ECustomer.cs | 16 +- Domain/Entities/ECustomerAddress.cs | 11 +- Domain/Entities/ECustomerDocument.cs | 10 +- Domain/Entities/EDocumentType.cs | 5 +- Domain/Entities/Tickets.cs | 5 +- Domain/Generics/CustomerSearchParams.cs | 9 + Domain/Generics/PagedRequest.cs | 8 +- Domain/Generics/PagedResult.cs | 1 - Models/Helpers/PaginationExtensions.cs | 1 - Models/Interfaces/IPhSCustomerRepository.cs | 6 - .../Controllers/Sales/CustomerController.cs | 21 ++- .../obj/Debug/net8.0/ApiEndpoints.json | 16 ++ .../Pages/Sales/CustomerForm.razor | 30 +--- .../Pages/Sales/Customers.razor | 164 ++++++++++++------ .../Services/Sales/CustomerService.cs | 53 +++++- 18 files changed, 266 insertions(+), 173 deletions(-) create mode 100644 Domain/Generics/CustomerSearchParams.cs diff --git a/Core/Interfaces/ICustomerDom.cs b/Core/Interfaces/ICustomerDom.cs index 75bdf9e..c1a4446 100644 --- a/Core/Interfaces/ICustomerDom.cs +++ b/Core/Interfaces/ICustomerDom.cs @@ -1,21 +1,17 @@ using Domain.Entities; using Domain.Generics; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Core.Interfaces { public interface ICustomerDom { Task CreateAsync(ECustomer entity); - Task DeleteAsync(int id); + Task UpdateAsync(ECustomer entity); Task> GetAllAsync(int page = 1, int pageSize = 50); Task GetByIdAsync(int id); Task> SearchAsync(string? name, string? email, string? document, int page = 1, int pageSize = 50); - Task UpdateAsync(ECustomer entity); + Task ExportFilteredCustomersToExcelAsync(CustomerSearchParams searchParams); + Task DeleteAsync(int id); } } diff --git a/Core/Services/CustomerService.cs b/Core/Services/CustomerService.cs index 3f63ebe..f7195a7 100644 --- a/Core/Services/CustomerService.cs +++ b/Core/Services/CustomerService.cs @@ -1,14 +1,9 @@ -using System.Drawing.Printing; -using System.Reflection; -using Azure; -using System.Reflection.Metadata; -using Core.Interfaces; +using Core.Interfaces; using Domain.Entities; using Domain.Generics; -using Microsoft.EntityFrameworkCore; -using Models.Helpers; using Models.Interfaces; -using Models.Models; +using System.Reflection; +using Transversal.Services; namespace Core.Services { @@ -21,6 +16,7 @@ namespace Core.Services _repository = customerRepository ?? throw new ArgumentNullException(nameof(customerRepository)); } #endregion + #region Metodos public async Task> GetAllAsync(int page = 1, int pageSize = 50) { try @@ -72,7 +68,6 @@ namespace Core.Services throw new Exception($"{methodName} Message: {ex.Message}", ex); } } - public async Task UpdateAsync(ECustomer entity) { if (entity is null) @@ -90,5 +85,49 @@ namespace Core.Services { throw new NotImplementedException(); } + public async Task ExportFilteredCustomersToExcelAsync(CustomerSearchParams searchParams) + { + try + { + // Realiza la búsqueda de clientes con los parámetros proporcionados + var searchResult = await SearchAsync( + searchParams.Name, + searchParams.Email, + searchParams.Document, + searchParams.Page, + searchParams.PageSize + ); + // Verifica que se hayan encontrado resultados + if (searchResult?.Items is null || !searchResult.Items.Any()) + { + throw new Exception("No se encontraron clientes para exportar."); + } + // Llamamos a un método que exporta los datos a Excel + var stream = new XLSXExportBase(); + // Convertimos los resultados de la búsqueda a un formato adecuado para el exportador + var customersData = searchResult.Items.Select(c => new + { + c.Id, + c.Name, + c.BusinessName, + c.Active, + c.HasCreditAccount, + c.CreditLimit, + Address = c.PhSCustomerAddresses.FirstOrDefault()?.Streetaddress1, + Email = c.PhSCustomerAddresses.FirstOrDefault()?.Email, + Document = c.PhSCustomerDocuments.FirstOrDefault()?.DocumentNumber + }).ToList(); + // Genera el archivo Excel + var excelFile = stream.ExportExcel(customersData); + // Devuelve el archivo Excel como un array de bytes + return excelFile; + } + catch (Exception ex) + { + var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod"; + throw new Exception($"{ex.Message}", ex); + } + } + #endregion } -} +} \ No newline at end of file diff --git a/Domain/Entities/EAccountType.cs b/Domain/Entities/EAccountType.cs index d51ab95..73117b1 100644 --- a/Domain/Entities/EAccountType.cs +++ b/Domain/Entities/EAccountType.cs @@ -1,23 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Domain.Entities +namespace Domain.Entities { public class EAccountType { public int Id { get; set; } - public string Name { get; set; } = null!; - public string? Description { get; set; } - public decimal? CreditLimit { get; set; } - public DateTime? CreationDate { get; set; } - - //public virtual ICollection Customers { get; set; } = new List(); } } diff --git a/Domain/Entities/ECustomer.cs b/Domain/Entities/ECustomer.cs index 1b7798a..65b1cfb 100644 --- a/Domain/Entities/ECustomer.cs +++ b/Domain/Entities/ECustomer.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - +using System.ComponentModel.DataAnnotations; namespace Domain.Entities { public class ECustomer @@ -18,20 +12,12 @@ namespace Domain.Entities public int? AccounttypesId { get; set; } [Required(ErrorMessage = "Debe seleccionar un condicion.")] public int? TaxConditionId { get; set; } - public bool HasCreditAccount { get; set; } - public decimal CreditLimit { get; set; } - public bool Active { get; set; } - public string? ExternalCode { get; set; } - public virtual EAccountType? Accounttypes { get; set; } - public virtual ICollection PhSCustomerAddresses { get; set; } = new List(); - public virtual ICollection PhSCustomerDocuments { get; set; } = new List(); - } } diff --git a/Domain/Entities/ECustomerAddress.cs b/Domain/Entities/ECustomerAddress.cs index ab51a57..267c9cc 100644 --- a/Domain/Entities/ECustomerAddress.cs +++ b/Domain/Entities/ECustomerAddress.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - +using System.ComponentModel.DataAnnotations; namespace Domain.Entities { public class ECustomerAddress @@ -26,5 +20,4 @@ namespace Domain.Entities public string? Email { get; set; } public string? Notes { get; set; } } - -} +} \ No newline at end of file diff --git a/Domain/Entities/ECustomerDocument.cs b/Domain/Entities/ECustomerDocument.cs index 2549f68..2aaae45 100644 --- a/Domain/Entities/ECustomerDocument.cs +++ b/Domain/Entities/ECustomerDocument.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - +using System.ComponentModel.DataAnnotations; namespace Domain.Entities { public class ECustomerDocument @@ -15,9 +9,7 @@ namespace Domain.Entities public int DocumenttypesId { get; set; } [Required(ErrorMessage = "Debe seleccionar un numero documento.")] public string DocumentNumber { get; set; } = null!; - public DateOnly? IssueDate { get; set; } - public DateOnly? ExpiryDate { get; set; } } } diff --git a/Domain/Entities/EDocumentType.cs b/Domain/Entities/EDocumentType.cs index 54735a2..f3b06bb 100644 --- a/Domain/Entities/EDocumentType.cs +++ b/Domain/Entities/EDocumentType.cs @@ -3,11 +3,8 @@ public class EDocumentType { public int Id { get; set; } - public string? Code { get; set; } - public string Name { get; set; } = null!; - public string? Description { get; set; } } -} +} \ No newline at end of file diff --git a/Domain/Entities/Tickets.cs b/Domain/Entities/Tickets.cs index bd95fe0..37cdc80 100644 --- a/Domain/Entities/Tickets.cs +++ b/Domain/Entities/Tickets.cs @@ -1,5 +1,4 @@ - -namespace Domain.Entities +namespace Domain.Entities { public class ETicket { @@ -39,4 +38,4 @@ namespace Domain.Entities public string Impacto { get; set; } = string.Empty; public string Urgencia { get; set; } = string.Empty; } -} +} \ No newline at end of file diff --git a/Domain/Generics/CustomerSearchParams.cs b/Domain/Generics/CustomerSearchParams.cs new file mode 100644 index 0000000..4f79296 --- /dev/null +++ b/Domain/Generics/CustomerSearchParams.cs @@ -0,0 +1,9 @@ +namespace Domain.Generics +{ + public class CustomerSearchParams : PagedRequest + { + public string? Name { get; set; } + public string? Email { get; set; } + public string? Document { get; set; } + } +} diff --git a/Domain/Generics/PagedRequest.cs b/Domain/Generics/PagedRequest.cs index 45a818c..d66cd9d 100644 --- a/Domain/Generics/PagedRequest.cs +++ b/Domain/Generics/PagedRequest.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Domain.Generics +namespace Domain.Generics { public class PagedRequest { diff --git a/Domain/Generics/PagedResult.cs b/Domain/Generics/PagedResult.cs index c6d1c51..efdd7ec 100644 --- a/Domain/Generics/PagedResult.cs +++ b/Domain/Generics/PagedResult.cs @@ -6,7 +6,6 @@ public int TotalItems { get; set; } public int Page { get; set; } public int PageSize { get; set; } - public int TotalPages => (int)Math.Ceiling((double)TotalItems / PageSize); } } diff --git a/Models/Helpers/PaginationExtensions.cs b/Models/Helpers/PaginationExtensions.cs index 9f16a75..b454454 100644 --- a/Models/Helpers/PaginationExtensions.cs +++ b/Models/Helpers/PaginationExtensions.cs @@ -15,7 +15,6 @@ namespace Models.Helpers .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); - return new PagedResult { Items = items, diff --git a/Models/Interfaces/IPhSCustomerRepository.cs b/Models/Interfaces/IPhSCustomerRepository.cs index 6c7bd60..d0832dd 100644 --- a/Models/Interfaces/IPhSCustomerRepository.cs +++ b/Models/Interfaces/IPhSCustomerRepository.cs @@ -1,11 +1,5 @@ using Domain.Entities; using Domain.Generics; -using Models.Models; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Models.Interfaces { diff --git a/phronCare.API/Controllers/Sales/CustomerController.cs b/phronCare.API/Controllers/Sales/CustomerController.cs index 6b006b1..97a68a1 100644 --- a/phronCare.API/Controllers/Sales/CustomerController.cs +++ b/phronCare.API/Controllers/Sales/CustomerController.cs @@ -1,6 +1,7 @@ using Core.Interfaces; using Domain.Entities; -using Microsoft.AspNetCore.Http; +using Domain.Generics; + using Microsoft.AspNetCore.Mvc; using System.Reflection; @@ -50,6 +51,7 @@ namespace phronCare.API.Controllers.Sales return StatusCode(500, $"{methodName} Message: {ex.Message}"); } } + [HttpGet("{id:int}")] public async Task> GetById(int id) { @@ -66,6 +68,7 @@ namespace phronCare.API.Controllers.Sales return StatusCode(500, $"Error: {ex.Message}"); } } + [HttpPost("create")] public async Task Create([FromBody] ECustomer customer) { @@ -91,6 +94,7 @@ namespace phronCare.API.Controllers.Sales return StatusCode(500, $"{methodName} Message: {ex.Message}"); } } + [HttpPut("update")] public async Task Update([FromBody] ECustomer customer) { @@ -112,5 +116,20 @@ namespace phronCare.API.Controllers.Sales return StatusCode(500, $"{methodName} Message: {ex.Message}"); } } + + [HttpPost("exportfiltered")] + public async Task ExportFiltered([FromBody] CustomerSearchParams searchParams) + { + try { + var file = await _customerService.ExportFilteredCustomersToExcelAsync(searchParams); + return File(file, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "Clientes.xlsx"); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } } } diff --git a/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json b/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json index cee6104..8a436f4 100644 --- a/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json +++ b/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json @@ -367,6 +367,22 @@ ], "ReturnTypes": [] }, + { + "ContainingType": "phronCare.API.Controllers.Sales.CustomerController", + "Method": "ExportFiltered", + "RelativePath": "api/Customer/exportfiltered", + "HttpMethod": "POST", + "IsController": true, + "Order": 0, + "Parameters": [ + { + "Name": "searchParams", + "Type": "Domain.Generics.CustomerSearchParams", + "IsRequired": true + } + ], + "ReturnTypes": [] + }, { "ContainingType": "phronCare.API.Controllers.Sales.CustomerController", "Method": "Search", diff --git a/phronCare.UIBlazor/Pages/Sales/CustomerForm.razor b/phronCare.UIBlazor/Pages/Sales/CustomerForm.razor index 1caedd4..7ab5372 100644 --- a/phronCare.UIBlazor/Pages/Sales/CustomerForm.razor +++ b/phronCare.UIBlazor/Pages/Sales/CustomerForm.razor @@ -4,16 +4,16 @@ @using phronCare.UIBlazor.Pages.Shared.Modals @using phronCare.UIBlazor.Services.Sales @inject IModalService Modal +@inject IToastService toastService @inject HttpClient _httpClient @inject NavigationManager Navigation -@inject IToastService toastService @inject AuthenticationStateProvider authenticationStateProvider @inject AccountTypeService accountTypeService @inject TaxConditionService taxConditionService -
-
-

Formulario: cliente

+
+
+

Información del cliente

@@ -231,21 +231,17 @@ @code { [Parameter] public int? CustomerId { get; set; } - private ECustomer customer { get; set; } = new(); private List accountTypes = new(); private List taxConditions = new(); private List documentTypes = new(); private ECustomerDocument documentFormModel = new(); private bool isSaving = false; - private string returnUrl = "/sales/customers"; - private List countries = new() { "Argentina", "Brasil", "Chile", "Uruguay", "Paraguay", "Estados Unidos", "Canadá", "México", "Alemania", "Reino Unido", "Francia", "Italia", "España" }; - private Dictionary> provincesByCountry = new() { { @@ -258,17 +254,14 @@ } } }; - private ECustomerAddress editingAddress = new(); private int editingIndex = -1; - private void OnCountryChanged(ChangeEventArgs e) { var selectedCountry = e.Value?.ToString(); editingAddress.Country = selectedCountry; editingAddress.Stateprovince = string.Empty; // Resetear la provincia si cambia el país } - private void AddOrUpdateAddress() { var context = new ValidationContext(editingAddress, null, null); @@ -292,7 +285,6 @@ { // Actualizar dirección existente var existing = customer.PhSCustomerAddresses.ElementAt(editingIndex); - existing.BusinessName = editingAddress.BusinessName; existing.Streetaddress1 = editingAddress.Streetaddress1; existing.Streetaddress2 = editingAddress.Streetaddress2; @@ -306,10 +298,8 @@ existing.Email = editingAddress.Email; existing.Notes = editingAddress.Notes; } - ResetAddressForm(); } - private void EditAddress(int index) { var addr = customer.PhSCustomerAddresses.ElementAt(index); @@ -333,26 +323,21 @@ editingIndex = index; } - private void RemoveAddress(int index) { var itemToRemove = customer.PhSCustomerAddresses.ElementAt(index); customer.PhSCustomerAddresses.Remove(itemToRemove); ResetAddressForm(); } - - private void CancelAddressEdit() { ResetAddressForm(); } - private void ResetAddressForm() { editingAddress = new(); editingIndex = -1; } - protected override async Task OnInitializedAsync() { await LoadAccountTypes(); @@ -365,7 +350,6 @@ customer = await _httpClient.GetFromJsonAsync($"/api/Customer/{CustomerId.Value}") ?? new(); } } - private async Task LoadAccountTypes() { accountTypes = await accountTypeService.GetAllAsync(); @@ -379,7 +363,6 @@ var result = await _httpClient.GetFromJsonAsync>("/api/DocumentType/GetAll"); documentTypes = result ?? new(); } - private void AddCustomerDocument() { if (!string.IsNullOrWhiteSpace(documentFormModel.DocumentNumber)) @@ -396,21 +379,17 @@ { customer.PhSCustomerAddresses.Remove(address); } - private async Task HandleValidSubmit() { var parameters = new ModalParameters(); parameters.Add("Message", "¿Desea guardar los cambios del cliente?"); - var modal = Modal.Show("Confirmacion", parameters); var result = await modal.Result; - if (result.Cancelled) return; try { HttpResponseMessage response; - if (CustomerId.HasValue) { response = await _httpClient.PutAsJsonAsync("/api/Customer/Update", customer); @@ -435,7 +414,6 @@ toastService.ShowError($"Error: {ex.Message}"); } } - private void Cancel() { Navigation.NavigateTo(returnUrl); diff --git a/phronCare.UIBlazor/Pages/Sales/Customers.razor b/phronCare.UIBlazor/Pages/Sales/Customers.razor index 42f58de..3d3344f 100644 --- a/phronCare.UIBlazor/Pages/Sales/Customers.razor +++ b/phronCare.UIBlazor/Pages/Sales/Customers.razor @@ -3,21 +3,34 @@ @using phronCare.UIBlazor.Data @using Domain.Entities @using Domain.Generics +@inject IToastService toastService @inject NavigationManager Navigation @inject CustomerService customerService -
-
-

Listado de clientes

@* wtf? *@ +
+
+

Administración de clientes

@* wtf? *@
-
-
+
+
- + + + +
- +
+
@if (TablaClientes != null && TablaClientes.Any()) { -
- - Página @SearchParams.Page de @TotalPaginas - -
} else {

No hay resultados.

} +
- @code { + protected override void OnInitialized() + { + botones = new List + { + new PhTable.ButtonOptions + { + Caption = "Editar", + ElementClass = "btn btn-primary btn-sm", + UrlAction = "/sales/customers/edit/", + OnClickAction = async (id) => + { + if (int.TryParse(id, out var customerId)) + { + Navigation.NavigateTo($"/sales/customerform/{customerId}"); + } + } + } + }; + } private CustomerSearchParams SearchParams = new(); private PagedResult? PagedResult; private List> TablaClientes = new(); @@ -62,13 +107,34 @@ "Id", "Nombre", "Activo", "Crédito", "Límite", "Email", "Teléfono", "Dirección", "Documento" }; + private int PaginaDeseada = 1; - private async Task BuscarClientes() + private async Task PrimeraPagina() { SearchParams.Page = 1; + await BuscarClientes(); + } + private async Task UltimaPagina() + { + SearchParams.Page = TotalPaginas; + await BuscarClientes(); + } + private async Task IrAPagina() + { + if (PaginaDeseada >= 1 && PaginaDeseada <= TotalPaginas) + { + SearchParams.Page = PaginaDeseada; + await BuscarClientes(); + } + else + { + toastService.ShowWarning("Número de página fuera de rango."); + } + } + private async Task BuscarClientes() + { await CargarClientes(); } - private async Task CargarClientes() { PagedResult = await customerService.SearchCustomersAsync(SearchParams); @@ -107,45 +173,39 @@ await CargarClientes(); } } - - private async Task XSLXExportar() + private async Task ExportarExcel() { - // string endpoint = "/api/Ticket/ExportDashboardDetail"; - // var response = await _httpClient.PostAsJsonAsync(endpoint, new { Param1 = Group, Param2 = "ASC" }); - // response.EnsureSuccessStatusCode(); - // var fileBytes = await response.Content.ReadAsByteArrayAsync(); - // var currentDate = DateTime.Now.ToString("ddMMyyyyhhmmss"); - // var filename = $"Tickets_{Group}_{currentDate}.xlsx"; - // await js.InvokeAsync("saveAsFile", filename, Convert.ToBase64String(fileBytes)); - } - - List botones = new(); - protected override void OnInitialized() - { - botones = new List - { - new PhTable.ButtonOptions + // Crea el objeto de parámetros para la búsqueda + var searchParams = new CustomerSearchParams { - Caption = "Editar", - ElementClass = "btn btn-primary btn-sm", - UrlAction = "/sales/customers/edit/", - OnClickAction = async (id) => - { - if (int.TryParse(id, out var customerId)) - { - Navigation.NavigateTo($"/sales/customerform/{customerId}"); - } - } - } - }; + Name = SearchParams.Name, // Aquí podés obtener los filtros de los campos en el formulario + Email = SearchParams.Email, + Document = SearchParams.Document, + Page = 1, + PageSize = int.MaxValue // Puedes ajustar el tamaño de la página para exportar todos los registros + }; + try + { + await customerService.ExportFilteredAsync(searchParams); + toastService.ShowSuccess("Exportación completada exitosamente."); + } + catch (Exception ex) + { + toastService.ShowError($"{ex.Message}"); + } } + + 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); - private bool PuedeAvanzar => PagedResult != null && SearchParams.Page < TotalPaginas; - private bool PuedeRetroceder => PagedResult != null && SearchParams.Page > 1; - + private void NuevoCliente() + { + Navigation.NavigateTo("/sales/customerform/"); + } public void Cancel() { Navigation.NavigateTo("/DashboardPanel"); } + List botones = new(); } \ No newline at end of file diff --git a/phronCare.UIBlazor/Services/Sales/CustomerService.cs b/phronCare.UIBlazor/Services/Sales/CustomerService.cs index 78f6cdc..c9cba35 100644 --- a/phronCare.UIBlazor/Services/Sales/CustomerService.cs +++ b/phronCare.UIBlazor/Services/Sales/CustomerService.cs @@ -1,14 +1,22 @@ using Domain.Entities; using Domain.Generics; 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 CustomerService { private readonly HttpClient _http; - public CustomerService(HttpClient http) + private readonly IJSRuntime _js; + public CustomerService(HttpClient http, IJSRuntime js) { _http = http; + _js = js; } public async Task?> SearchCustomersAsync(CustomerSearchParams searchParams) { @@ -20,13 +28,40 @@ namespace phronCare.UIBlazor.Services.Sales $"pageSize={searchParams.PageSize}"; return await _http.GetFromJsonAsync>(url); } + public async Task ExportFilteredAsync(CustomerSearchParams searchParams) + { + try + { + var content = new StringContent(JsonSerializer.Serialize(searchParams), Encoding.UTF8, "application/json"); + var response = await _http.PostAsync("api/Customer/exportfiltered", content); + + //response.EnsureSuccessStatusCode(); + 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}_clientes.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); + } + } } - public class CustomerSearchParams - { - public string? Name { get; set; } - public string? Email { get; set; } - public string? Document { get; set; } - public int Page { get; set; } = 1; - public int PageSize { get; set; } = 10; - } + + //public class CustomerSearchParams + //{ + // public string? Name { get; set; } + // public string? Email { get; set; } + // public string? Document { get; set; } + // public int Page { get; set; } = 1; + // public int PageSize { get; set; } = 10; + //} }