diff --git a/Core/Interfaces/Stock/IExpeditionDom.cs b/Core/Interfaces/Stock/IExpeditionDom.cs index e308276..4f4618e 100644 --- a/Core/Interfaces/Stock/IExpeditionDom.cs +++ b/Core/Interfaces/Stock/IExpeditionDom.cs @@ -23,5 +23,6 @@ namespace Core.Interfaces.Stock ELSExpeditionHeader header, IEnumerable details, int formSeriesId); + Task ExportFilteredToExcelAsync(ExpeditionSearchParams searchParams); } } diff --git a/Core/Services/Stock/ExpeditionService.cs b/Core/Services/Stock/ExpeditionService.cs index 5451ec9..ddba93a 100644 --- a/Core/Services/Stock/ExpeditionService.cs +++ b/Core/Services/Stock/ExpeditionService.cs @@ -3,6 +3,8 @@ using Domain.Dtos.Stock; using Domain.Entities; using Domain.Generics; using Models.Interfaces; +using System.Reflection; +using Transversal.Services; namespace Core.Services.Stock { @@ -47,5 +49,53 @@ namespace Core.Services.Stock => _repo.SearchAsync(expeditionNumber, status, issueDateFrom, issueDateTo, locationId, page, pageSize); public Task GetDtoByIdAsync(int id) => _repo.GetDtoByIdAsync(id); + + public async Task ExportFilteredToExcelAsync(ExpeditionSearchParams searchParams) + { + try + { + // Realiza la búsqueda de clientes con los parámetros proporcionados + var searchResult = await SearchAsync( + searchParams.Number, + searchParams.Status, + searchParams.From, + searchParams.To, + searchParams.LocationId, + 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 items = searchResult.Items.Select(c => new + { + c.Expeditionnumber, + Issuedate = c.Issuedate.ToString("yyyy-MM-dd"), // ← string + Createdat = c.Createdat.ToString("yyyy-MM-dd HH:mm"), // ← string + + c.Status, + c.LocationId, + c.ExternalReference, + c.TicketId, + c.ExtrainfoJson, + c.Observations, + c.TotalItems + }).ToList(); + // Genera el archivo Excel + var excelFile = stream.ExportExcel(items); + // 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); + } + } } } diff --git a/Domain/Generics/ExpeditionSearchParams.cs b/Domain/Generics/ExpeditionSearchParams.cs new file mode 100644 index 0000000..f176aa9 --- /dev/null +++ b/Domain/Generics/ExpeditionSearchParams.cs @@ -0,0 +1,12 @@ +namespace Domain.Generics +{ + public class ExpeditionSearchParams:PagedRequest + { + public string? Number { get; set; } + public string? Status { get; set; } + public DateTime? From { get; set; } + public DateTime? To { get; set; } + public int? LocationId { get; set; } + + } +} diff --git a/Transversal/Services/XLSXExportBase.cs b/Transversal/Services/XLSXExportBase.cs index 831b05d..9ac595c 100644 --- a/Transversal/Services/XLSXExportBase.cs +++ b/Transversal/Services/XLSXExportBase.cs @@ -10,7 +10,7 @@ namespace Transversal.Services ExcelPackage.LicenseContext = LicenseContext.NonCommercial; using (var package = new ExcelPackage()) { - var worksheet = package.Workbook.Worksheets.Add("Datos"); + var worksheet = package.Workbook.Worksheets.Add("datos"); // Obtener las propiedades de T var propiedades = typeof(T).GetProperties(); diff --git a/phronCare.API/Controllers/Stock/ExpeditionController.cs b/phronCare.API/Controllers/Stock/ExpeditionController.cs index 342aa31..581e5a1 100644 --- a/phronCare.API/Controllers/Stock/ExpeditionController.cs +++ b/phronCare.API/Controllers/Stock/ExpeditionController.cs @@ -81,8 +81,6 @@ namespace phronCare.API.Controllers.Stock if (dto is null) return NotFound($"No se encontró expedición {expeditionNumber}."); return Ok(dto); } - - #region Endpoint de emision de expedicion (encabezado + detalles) [HttpPost("createfull")] public async Task CreateFullExpedition([FromBody] CreateFullExpeditionRequest request) @@ -111,7 +109,6 @@ namespace phronCare.API.Controllers.Stock } } #endregion - /// /// Genera y devuelve un archivo PDF correspondiente al presupuesto especificado por su ID. /// @@ -131,6 +128,22 @@ namespace phronCare.API.Controllers.Stock return File(pdfBytes, "application/pdf", $"Expedicion_{expedition.Expeditionnumber}.pdf"); } + [HttpPost("exportfiltered")] + + public async Task ExportFiltered([FromBody] ExpeditionSearchParams searchParams) + { + try + { + var file = await _expeditionService.ExportFilteredToExcelAsync(searchParams); + return File(file, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "Expediciones.xlsx"); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } } public class CreateFullExpeditionRequest { diff --git a/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json b/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json index 1e2d005..7da4172 100644 --- a/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json +++ b/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json @@ -694,6 +694,22 @@ ], "ReturnTypes": [] }, + { + "ContainingType": "phronCare.API.Controllers.Stock.ExpeditionController", + "Method": "ExportFiltered", + "RelativePath": "api/Expedition/exportfiltered", + "HttpMethod": "POST", + "IsController": true, + "Order": 0, + "Parameters": [ + { + "Name": "searchParams", + "Type": "Domain.Generics.ExpeditionSearchParams", + "IsRequired": true + } + ], + "ReturnTypes": [] + }, { "ContainingType": "phronCare.API.Controllers.Stock.ExpeditionController", "Method": "Search", diff --git a/phronCare.UIBlazor/Pages/Stock/Expeditions/Expeditions.razor b/phronCare.UIBlazor/Pages/Stock/Expeditions/Expeditions.razor index 8df3caa..692195e 100644 --- a/phronCare.UIBlazor/Pages/Stock/Expeditions/Expeditions.razor +++ b/phronCare.UIBlazor/Pages/Stock/Expeditions/Expeditions.razor @@ -5,7 +5,7 @@ @using System.Text.Json @using phronCare.UIBlazor.Services.Stock.Expeditions -@inject ExpeditionService expeditionService +@inject IExpeditionService expeditionService @inject NavigationManager Nav @inject IToastService Toast @@ -71,14 +71,13 @@ + - - @@ -167,6 +166,8 @@ Loading="@loadingDetail" /> @code { + private LSProductSearchParams SearchParams = new() { Page = 1, PageSize = 10 }; + private Filters filters = new(); private PagedResult? result; private int page = 1; @@ -225,11 +226,26 @@ Nav.NavigateTo("/expeditions/create"); } - private async Task ExportCurrent() - { - // Opcional: /api/lsm/expeditions/export?{filtros} - Toast.ShowInfo("Export en preparación."); - } + private async Task ExportarExcel() + { + SearchParams.Page = 1; + SearchParams.PageSize = int.MaxValue; // Exportar todos los resultados + try + { + await expeditionService.ExportFilteredAsync(SearchParams); + Toast.ShowSuccess("Exportación completada."); + } + catch (Exception ex) + { + Toast.ShowError($"Error: {ex.Message}"); + } + } + + // private async Task ExportCurrent() + // { + // // Opcional: /api/lsm/expeditions/export?{filtros} + // Toast.ShowInfo("Export en preparación."); + // } private async Task ViewPdf(int id, string number) { diff --git a/phronCare.UIBlazor/Program.cs b/phronCare.UIBlazor/Program.cs index 0fa1273..066ba96 100644 --- a/phronCare.UIBlazor/Program.cs +++ b/phronCare.UIBlazor/Program.cs @@ -53,6 +53,7 @@ static void InjectDependencies(WebAssemblyHostBuilder builder) builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/phronCare.UIBlazor/Services/Stock/Expeditions/ExpeditionService.cs b/phronCare.UIBlazor/Services/Stock/Expeditions/ExpeditionService.cs index 73ef64b..410d8ea 100644 --- a/phronCare.UIBlazor/Services/Stock/Expeditions/ExpeditionService.cs +++ b/phronCare.UIBlazor/Services/Stock/Expeditions/ExpeditionService.cs @@ -4,6 +4,9 @@ using Domain.Entities; using Domain.Generics; using Microsoft.JSInterop; using System.Net.Http.Json; +using System.Reflection; +using System.Text; +using System.Text.Json; namespace phronCare.UIBlazor.Services.Stock.Expeditions { @@ -53,6 +56,7 @@ namespace phronCare.UIBlazor.Services.Stock.Expeditions var result = await _http.GetFromJsonAsync>(url); return result!; } + /// /// Obtiene un presupuesto por QuoteNumber. /// @@ -148,10 +152,37 @@ namespace phronCare.UIBlazor.Services.Stock.Expeditions throw new Exception($"ExportPdfAsync: {message}", ex); } } + + public async Task ExportFilteredAsync(LSProductSearchParams searchParams) + { + try + { + var content = new StringContent(JsonSerializer.Serialize(searchParams), Encoding.UTF8, "application/json"); + var response = await _http.PostAsync("api/Expedition/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}_expeditions.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); + } + } } /// - /// Contrato de request simétrico a CreateFullQuoteRequest. + /// Contrato de request. /// public class CreateFullExpeditionRequest { @@ -160,7 +191,7 @@ namespace phronCare.UIBlazor.Services.Stock.Expeditions } /// - /// Resultado del create/issue simétrico a CreateQuoteResult. + /// Resultado del create/issue. /// public class CreateExpeditionResult { @@ -170,6 +201,4 @@ namespace phronCare.UIBlazor.Services.Stock.Expeditions public string ErrorMessage { get; set; } = string.Empty; } - // TODO: Ajustar namespace real si es distinto - } \ No newline at end of file diff --git a/phronCare.UIBlazor/Services/Stock/Expeditions/IExpeditionService.cs b/phronCare.UIBlazor/Services/Stock/Expeditions/IExpeditionService.cs index 1fa4d08..5fdfd19 100644 --- a/phronCare.UIBlazor/Services/Stock/Expeditions/IExpeditionService.cs +++ b/phronCare.UIBlazor/Services/Stock/Expeditions/IExpeditionService.cs @@ -10,5 +10,6 @@ namespace phronCare.UIBlazor.Services.Stock.Expeditions Task GetDtoByIdAsync(int id); Task GetQuoteByNumberAsync(string quoteNumber); Task> SearchAsync(string? expeditionNumber = null, string? status = null, DateTime? issueDateFrom = null, DateTime? issueDateTo = null, int? locationId = null, int page = 1, int pageSize = 10); + Task ExportFilteredAsync(LSProductSearchParams searchParams); } }