Add Download Template Product
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 14m19s

This commit is contained in:
Leandro Hernan Rojas 2025-07-05 13:26:22 -03:00
parent d60238f5eb
commit 27439cbd95
8 changed files with 90 additions and 3 deletions

View File

@ -11,5 +11,6 @@ namespace Core.Interfaces
Task<bool> UpdateAsync(ELSProduct entity); Task<bool> UpdateAsync(ELSProduct entity);
Task<bool> DeleteAsync(int id); Task<bool> DeleteAsync(int id);
Task<byte[]> ExportToExcelAsync(LSProductSearchParams searchParams); Task<byte[]> ExportToExcelAsync(LSProductSearchParams searchParams);
byte[] GetImportTemplate();
} }
} }

View File

@ -77,5 +77,16 @@ namespace Core.Services
throw new Exception($"Error en {method}: {ex.Message}", ex); throw new Exception($"Error en {method}: {ex.Message}", ex);
} }
} }
public byte[] GetImportTemplate()
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "Resources", "Templates", "Stock", "plantilla_productos.xlsx");
if (!File.Exists(path))
throw new FileNotFoundException("No se encontró la plantilla de importación de productos.", path);
return File.ReadAllBytes(path);
}
} }
} }

View File

@ -64,5 +64,14 @@ namespace API.Controllers.Stock
var fileName = $"productos_{DateTime.Now:yyyyMMddHHmm}.xlsx"; var fileName = $"productos_{DateTime.Now:yyyyMMddHHmm}.xlsx";
return File(content, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName); return File(content, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
} }
[HttpGet("download-template")]
public IActionResult DownloadImportTemplate()
{
var file = _service.GetImportTemplate();
return File(file,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"plantilla_productos.xlsx");
}
} }
} }

View File

@ -1080,6 +1080,16 @@
} }
] ]
}, },
{
"ContainingType": "API.Controllers.Stock.LSProductController",
"Method": "DownloadImportTemplate",
"RelativePath": "api/LSProduct/download-template",
"HttpMethod": "GET",
"IsController": true,
"Order": 0,
"Parameters": [],
"ReturnTypes": []
},
{ {
"ContainingType": "API.Controllers.Stock.LSProductController", "ContainingType": "API.Controllers.Stock.LSProductController",
"Method": "ExportFiltered", "Method": "ExportFiltered",

View File

@ -19,6 +19,11 @@
<ItemGroup> <ItemGroup>
<Content Include="Resources\logo.png" /> <Content Include="Resources\logo.png" />
<Content Include="Resources\Templates\Stock\plantilla_productos.xlsx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,13 +1,17 @@
@page "/stock/productimport" @page "/stock/productimport"
@using phronCare.UIBlazor.Services.Stock
@inject IJSRuntime JS @inject IJSRuntime JS
@inject IToastService toastService
@inject NavigationManager Navigation @inject NavigationManager Navigation
@inject LSProductService productService
<h3 class="mb-4">Importación masiva de productos</h3> <h3 class="mb-4">Importación masiva de productos</h3>
<div class="mb-3"> <div class="mb-3">
<button class="btn btn-primary" @onclick="DownloadTemplate">Descargar plantilla Excel</button> <button class="btn btn-primary" @onclick="DownloadTemplate">Descargar plantilla Excel</button>
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label for="fileUpload" class="form-label fw-semibold">Seleccionar archivo Excel</label> <label for="fileUpload" class="form-label fw-semibold">Seleccionar archivo Excel</label>
<div class="input-group"> <div class="input-group">
@ -16,6 +20,13 @@
</div> </div>
</div> </div>
@if (UploadedFile != null)
{
<div class="mb-4">
<button class="btn btn-warning" @onclick="ProcessFile">Procesar archivo Excel</button>
</div>
}
@if (PreviewItems != null) @if (PreviewItems != null)
{ {
<h5 class="mt-4">Vista previa</h5> <h5 class="mt-4">Vista previa</h5>
@ -61,6 +72,8 @@
@code { @code {
private List<ProductImportPreviewDto>? PreviewItems; private List<ProductImportPreviewDto>? PreviewItems;
private IBrowserFile? UploadedFile;
protected override void OnInitialized() protected override void OnInitialized()
{ {
PreviewItems = new List<ProductImportPreviewDto> PreviewItems = new List<ProductImportPreviewDto>
@ -72,14 +85,37 @@
new() { FactoryCode = "ZIM005", Name = "Perno cortical", Description = "Perno de fijación", ProductType = 1, TraceabilityType = 3, DivisionCode = "ZIM", UnitCode = "UN", PlusProcess = true, ExternalCode = "EXT005" } new() { FactoryCode = "ZIM005", Name = "Perno cortical", Description = "Perno de fijación", ProductType = 1, TraceabilityType = 3, DivisionCode = "ZIM", UnitCode = "UN", PlusProcess = true, ExternalCode = "EXT005" }
}; };
} }
private async Task DownloadTemplate() private async Task DownloadTemplate()
{ {
Navigation.NavigateTo("api/LSProductImport/download-template", forceLoad: true); try
{
await productService.DownloadTemplateAsync();
}
catch (Exception ex)
{
toastService.ShowError($"Error al descargar la plantilla: {ex.Message}");
}
} }
private async Task HandleFileSelected(InputFileChangeEventArgs e) private async Task HandleFileSelected(InputFileChangeEventArgs e)
{ {
// Lógica futura para parsear y enviar archivo al backend UploadedFile = e.File;
//PreviewItems = null; // Limpiar preview anterior
}
private async Task ProcessFile()
{
if (UploadedFile == null) return;
using var stream = UploadedFile.OpenReadStream(10 * 1024 * 1024);
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var content = ms.ToArray();
// Aquí deberías llamar al backend para validar y obtener la vista previa
// Por ahora se simula con los datos ya cargados en OnInitialized
// PreviewItems = await Http.PostAsJsonAsync(...)
} }
private async Task SimulateImport() private async Task SimulateImport()

View File

@ -73,5 +73,20 @@ namespace phronCare.UIBlazor.Services.Stock
throw new Exception($"{message}", ex); throw new Exception($"{message}", ex);
} }
} }
public async Task DownloadTemplateAsync()
{
var response = await _http.GetAsync("/api/LSProduct/download-template");
if (!response.IsSuccessStatusCode)
{
var errorContent = await response.Content.ReadAsStringAsync();
throw new Exception($"No se pudo descargar la plantilla: {errorContent}");
}
var bytes = await response.Content.ReadAsByteArrayAsync();
var base64 = Convert.ToBase64String(bytes);
await _js.InvokeVoidAsync("saveAsFile", "plantilla_productos.xlsx", base64);
}
} }
} }