Add Export Exoeditions
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 21m48s
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 21m48s
This commit is contained in:
parent
813bcc24b1
commit
c2bd8247a1
@ -23,5 +23,6 @@ namespace Core.Interfaces.Stock
|
||||
ELSExpeditionHeader header,
|
||||
IEnumerable<ELSExpeditionDetail> details,
|
||||
int formSeriesId);
|
||||
Task<byte[]> ExportFilteredToExcelAsync(ExpeditionSearchParams searchParams);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<ExpeditionDto?> GetDtoByIdAsync(int id)
|
||||
=> _repo.GetDtoByIdAsync(id);
|
||||
|
||||
public async Task<byte[]> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
Domain/Generics/ExpeditionSearchParams.cs
Normal file
12
Domain/Generics/ExpeditionSearchParams.cs
Normal file
@ -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; }
|
||||
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -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<IActionResult> CreateFullExpedition([FromBody] CreateFullExpeditionRequest request)
|
||||
@ -111,7 +109,6 @@ namespace phronCare.API.Controllers.Stock
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Genera y devuelve un archivo PDF correspondiente al presupuesto especificado por su ID.
|
||||
/// </summary>
|
||||
@ -131,6 +128,22 @@ namespace phronCare.API.Controllers.Stock
|
||||
|
||||
return File(pdfBytes, "application/pdf", $"Expedicion_{expedition.Expeditionnumber}.pdf");
|
||||
}
|
||||
[HttpPost("exportfiltered")]
|
||||
|
||||
public async Task<IActionResult> 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
|
||||
{
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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 @@
|
||||
</button>
|
||||
<button class="btn btn-success rounded-pill" @onclick="Create">
|
||||
<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="Clear">
|
||||
<i class="fas fa-arrow-left me-1"></i> Volver
|
||||
</button>
|
||||
<button class="btn btn-success rounded-pill" @onclick="ExportCurrent">
|
||||
<i class="fas fa-file-excel me-1"></i> Excel
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</EditForm>
|
||||
</div>
|
||||
@ -167,6 +166,8 @@
|
||||
Loading="@loadingDetail" />
|
||||
|
||||
@code {
|
||||
private LSProductSearchParams SearchParams = new() { Page = 1, PageSize = 10 };
|
||||
|
||||
private Filters filters = new();
|
||||
private PagedResult<ExpeditionDto>? 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)
|
||||
{
|
||||
|
||||
@ -53,6 +53,7 @@ static void InjectDependencies(WebAssemblyHostBuilder builder)
|
||||
builder.Services.AddScoped<IStockLookUpService, StockLookUpService>();
|
||||
builder.Services.AddScoped<IExchangeRateService, ExchangeRateService>();
|
||||
builder.Services.AddScoped<IStockScanService, StockScanService>();
|
||||
builder.Services.AddScoped<IExpeditionService, ExpeditionService>();
|
||||
|
||||
builder.Services.AddScoped<ExchangeRateService>();
|
||||
builder.Services.AddScoped<QuoteService>();
|
||||
|
||||
@ -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<PagedResult<ExpeditionDto>>(url);
|
||||
return result!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtiene un presupuesto por QuoteNumber.
|
||||
/// </summary>
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contrato de request simétrico a CreateFullQuoteRequest.
|
||||
/// Contrato de request.
|
||||
/// </summary>
|
||||
public class CreateFullExpeditionRequest
|
||||
{
|
||||
@ -160,7 +191,7 @@ namespace phronCare.UIBlazor.Services.Stock.Expeditions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resultado del create/issue simétrico a CreateQuoteResult.
|
||||
/// Resultado del create/issue.
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
}
|
||||
@ -10,5 +10,6 @@ namespace phronCare.UIBlazor.Services.Stock.Expeditions
|
||||
Task<ExpeditionDto?> GetDtoByIdAsync(int id);
|
||||
Task<QuoteDto?> GetQuoteByNumberAsync(string quoteNumber);
|
||||
Task<PagedResult<ExpeditionDto>> 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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user