diff --git a/Core/Interfaces/Stock/ILSProductDom.cs b/Core/Interfaces/Stock/ILSProductDom.cs index bba90cd..4c76f25 100644 --- a/Core/Interfaces/Stock/ILSProductDom.cs +++ b/Core/Interfaces/Stock/ILSProductDom.cs @@ -11,5 +11,6 @@ namespace Core.Interfaces Task UpdateAsync(ELSProduct entity); Task DeleteAsync(int id); Task ExportToExcelAsync(LSProductSearchParams searchParams); + byte[] GetImportTemplate(); } } \ No newline at end of file diff --git a/Core/Services/Stock/LSProductService.cs b/Core/Services/Stock/LSProductService.cs index 335456b..a9cd721 100644 --- a/Core/Services/Stock/LSProductService.cs +++ b/Core/Services/Stock/LSProductService.cs @@ -77,5 +77,16 @@ namespace Core.Services 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); + } + + } } diff --git a/phronCare.API/Controllers/Stock/LSProductController.cs b/phronCare.API/Controllers/Stock/LSProductController.cs index ccf762d..4c01c38 100644 --- a/phronCare.API/Controllers/Stock/LSProductController.cs +++ b/phronCare.API/Controllers/Stock/LSProductController.cs @@ -64,5 +64,14 @@ namespace API.Controllers.Stock var fileName = $"productos_{DateTime.Now:yyyyMMddHHmm}.xlsx"; 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"); + } } } diff --git a/phronCare.API/Resources/Templates/Stock/plantilla_productos.xlsx b/phronCare.API/Resources/Templates/Stock/plantilla_productos.xlsx new file mode 100644 index 0000000..7019c44 Binary files /dev/null and b/phronCare.API/Resources/Templates/Stock/plantilla_productos.xlsx differ diff --git a/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json b/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json index 89e1f28..0351352 100644 --- a/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json +++ b/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json @@ -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", "Method": "ExportFiltered", diff --git a/phronCare.API/phronCare.API.csproj b/phronCare.API/phronCare.API.csproj index 7dbd028..f1096a3 100644 --- a/phronCare.API/phronCare.API.csproj +++ b/phronCare.API/phronCare.API.csproj @@ -19,6 +19,11 @@ + + Always + true + PreserveNewest + diff --git a/phronCare.UIBlazor/Pages/Stock/ProductImport.razor b/phronCare.UIBlazor/Pages/Stock/ProductImport.razor index fcf391d..fe1b296 100644 --- a/phronCare.UIBlazor/Pages/Stock/ProductImport.razor +++ b/phronCare.UIBlazor/Pages/Stock/ProductImport.razor @@ -1,13 +1,17 @@ @page "/stock/productimport" +@using phronCare.UIBlazor.Services.Stock @inject IJSRuntime JS +@inject IToastService toastService @inject NavigationManager Navigation +@inject LSProductService productService

Importación masiva de productos

+
@@ -16,6 +20,13 @@
+@if (UploadedFile != null) +{ +
+ +
+} + @if (PreviewItems != null) {
Vista previa
@@ -61,6 +72,8 @@ @code { private List? PreviewItems; + private IBrowserFile? UploadedFile; + protected override void OnInitialized() { PreviewItems = new List @@ -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" } }; } + 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) { - // 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() diff --git a/phronCare.UIBlazor/Services/Stock/LSProductService.cs b/phronCare.UIBlazor/Services/Stock/LSProductService.cs index 62fd7f7..499b3b9 100644 --- a/phronCare.UIBlazor/Services/Stock/LSProductService.cs +++ b/phronCare.UIBlazor/Services/Stock/LSProductService.cs @@ -73,5 +73,20 @@ namespace phronCare.UIBlazor.Services.Stock 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); + } + +} }