Update Transversal PDFGenerator
This commit is contained in:
parent
c9bfaca76d
commit
e7069b3848
1
.gitignore
vendored
1
.gitignore
vendored
@ -423,3 +423,4 @@ FodyWeavers.xsd
|
|||||||
/Domain/obj/Domain.csproj.nuget.g.props
|
/Domain/obj/Domain.csproj.nuget.g.props
|
||||||
/Models/obj/Models.csproj.nuget.g.props
|
/Models/obj/Models.csproj.nuget.g.props
|
||||||
/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json
|
/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json
|
||||||
|
/phronCare.API/.local-chromium/Win64-884014/chrome-win
|
||||||
|
|||||||
@ -16,4 +16,7 @@
|
|||||||
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.10\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.10\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props')" />
|
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.10\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.10\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props')" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<PkgNewtonsoft_Json Condition=" '$(PkgNewtonsoft_Json)' == '' ">C:\Users\maski\.nuget\packages\newtonsoft.json\10.0.3</PkgNewtonsoft_Json>
|
||||||
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -7,7 +7,7 @@
|
|||||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.1</NuGetToolVersion>
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.2</NuGetToolVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.1</NuGetToolVersion>
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.2</NuGetToolVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
||||||
|
|||||||
26
Transversal/Interfaces/IPdfGeneratorService.cs
Normal file
26
Transversal/Interfaces/IPdfGeneratorService.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using Transversal.Models;
|
||||||
|
|
||||||
|
namespace Transversal.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Define el contrato para un servicio generador de PDFs a partir de contenido HTML.
|
||||||
|
/// </summary>
|
||||||
|
public interface IPdfGeneratorService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Genera un documento PDF a partir de una cadena HTML.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="htmlContent">
|
||||||
|
/// Contenido HTML completo (incluyendo etiquetas <html>, <head>, <body>, etc.) que se desea convertir a PDF.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="options">
|
||||||
|
/// Opcional: configuración personalizada para el documento PDF (tamaño de papel, orientación, márgenes, encabezados, pies de página, etc.).
|
||||||
|
/// Si se deja en null, se aplica la configuración por defecto (A4, vertical, sin márgenes personalizados).
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// Un array de bytes que representa el documento PDF generado.
|
||||||
|
/// Puede ser utilizado para guardar en disco, devolver en una API como FileContentResult, etc.
|
||||||
|
/// </returns>
|
||||||
|
Task<byte[]> GeneratePdfFromHtmlAsync(string htmlContent, PdfGenerationOptions options = null);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Transversal/Models/PdfGenerationOptions.cs
Normal file
15
Transversal/Models/PdfGenerationOptions.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using PuppeteerSharp.Media;
|
||||||
|
|
||||||
|
namespace Transversal.Models
|
||||||
|
{
|
||||||
|
public class PdfGenerationOptions
|
||||||
|
{
|
||||||
|
public PaperFormat Format { get; set; } = PaperFormat.A4;
|
||||||
|
public bool Landscape { get; set; } = false;
|
||||||
|
public bool PrintBackground { get; set; } = true;
|
||||||
|
public decimal Scale { get; set; } = 1.0m;
|
||||||
|
public MarginOptions Margins { get; set; } = null;
|
||||||
|
public string HeaderTemplate { get; set; } = null;
|
||||||
|
public string FooterTemplate { get; set; } = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Transversal.Services
|
|
||||||
{
|
|
||||||
internal class Class1
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
57
Transversal/Services/PuppeteerPdfGeneratorService.cs
Normal file
57
Transversal/Services/PuppeteerPdfGeneratorService.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using Transversal.Interfaces;
|
||||||
|
using Transversal.Models;
|
||||||
|
using PuppeteerSharp;
|
||||||
|
using PuppeteerSharp.Media;
|
||||||
|
|
||||||
|
namespace Transversal.Services
|
||||||
|
{
|
||||||
|
public class PuppeteerPdfGeneratorService : IPdfGeneratorService, IAsyncDisposable
|
||||||
|
{
|
||||||
|
private readonly Browser _browser;
|
||||||
|
|
||||||
|
public PuppeteerPdfGeneratorService()
|
||||||
|
{
|
||||||
|
// Descargar Chromium si no está
|
||||||
|
new BrowserFetcher().DownloadAsync().GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
// Lanzar Chromium persistente
|
||||||
|
_browser = Puppeteer.LaunchAsync(new LaunchOptions
|
||||||
|
{
|
||||||
|
Headless = true,
|
||||||
|
Args = new[]
|
||||||
|
{
|
||||||
|
"--no-sandbox",
|
||||||
|
"--disable-setuid-sandbox"
|
||||||
|
}
|
||||||
|
}).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
public async Task<byte[]> GeneratePdfFromHtmlAsync(string htmlContent, PdfGenerationOptions options = null)
|
||||||
|
{
|
||||||
|
options ??= new PdfGenerationOptions();
|
||||||
|
|
||||||
|
using var page = await _browser.NewPageAsync();
|
||||||
|
await page.SetContentAsync(htmlContent);
|
||||||
|
|
||||||
|
var pdfOptions = new PdfOptions
|
||||||
|
{
|
||||||
|
Format = options.Format,
|
||||||
|
Landscape = options.Landscape,
|
||||||
|
PrintBackground = options.PrintBackground,
|
||||||
|
Scale = options.Scale,
|
||||||
|
MarginOptions = options.Margins ?? new MarginOptions(),
|
||||||
|
DisplayHeaderFooter = !string.IsNullOrEmpty(options.HeaderTemplate)
|
||||||
|
|| !string.IsNullOrEmpty(options.FooterTemplate),
|
||||||
|
HeaderTemplate = options.HeaderTemplate,
|
||||||
|
FooterTemplate = options.FooterTemplate
|
||||||
|
};
|
||||||
|
|
||||||
|
return await page.PdfDataAsync(pdfOptions);
|
||||||
|
}
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (_browser != null)
|
||||||
|
await _browser.CloseAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="EPPlus" Version="7.5.2" />
|
<PackageReference Include="EPPlus" Version="8.0.4" />
|
||||||
|
<PackageReference Include="PuppeteerSharp" Version="6.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -7,10 +7,13 @@
|
|||||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.2</NuGetToolVersion>
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.1</NuGetToolVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
||||||
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
|
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<PkgNewtonsoft_Json Condition=" '$(PkgNewtonsoft_Json)' == '' ">C:\Users\maski\.nuget\packages\newtonsoft.json\10.0.3</PkgNewtonsoft_Json>
|
||||||
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
103
phronCare.API/Controllers/PdfTestController.cs
Normal file
103
phronCare.API/Controllers/PdfTestController.cs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Transversal.Interfaces;
|
||||||
|
|
||||||
|
namespace phronCare.API.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class PdfTestController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IPdfGeneratorService _pdfGeneratorService;
|
||||||
|
|
||||||
|
public PdfTestController(IPdfGeneratorService pdfGeneratorService)
|
||||||
|
{
|
||||||
|
_pdfGeneratorService = pdfGeneratorService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("test")]
|
||||||
|
public async Task<IActionResult> GetTestPdf()
|
||||||
|
{
|
||||||
|
// HTML de ejemplo
|
||||||
|
string html = @"
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; font-size: 12px; margin: 20px; }
|
||||||
|
.header { text-align: center; border-bottom: 3px solid #4CAF50; padding-bottom: 10px; margin-bottom: 30px; }
|
||||||
|
.header h1 { color: #4CAF50; margin: 0; }
|
||||||
|
.info-table, .details-table, .totals-table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
|
||||||
|
.info-table td { padding: 5px; }
|
||||||
|
.details-table th, .details-table td { border: 1px solid #ddd; padding: 8px; text-align: center; }
|
||||||
|
.details-table th { background-color: #4CAF50; color: white; }
|
||||||
|
.totals-table th, .totals-table td { border: 1px solid #ddd; padding: 8px; text-align: right; }
|
||||||
|
.totals-table th { background-color: #4CAF50; color: white; }
|
||||||
|
.footer { position: fixed; bottom: 15px; left: 0; right: 0; text-align: center; font-size: 10px; color: gray; border-top: 1px solid #ddd; padding-top: 5px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class='header'>
|
||||||
|
<h1>PhronCare Ortopedia</h1>
|
||||||
|
<p>Presupuesto médico de prueba</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class='info-table'>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Cliente:</strong> Juan Pérez</td>
|
||||||
|
<td><strong>Presupuesto N°:</strong> 000123</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Fecha:</strong> 13/05/2025</td>
|
||||||
|
<td><strong>Profesional:</strong> Dr. Carlos López</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class='details-table'>
|
||||||
|
<tr>
|
||||||
|
<th>Cantidad</th>
|
||||||
|
<th>Producto</th>
|
||||||
|
<th>Precio Unitario</th>
|
||||||
|
<th>Subtotal</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2</td>
|
||||||
|
<td>Rodillera ortopédica</td>
|
||||||
|
<td>$5.000</td>
|
||||||
|
<td>$10.000</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>1</td>
|
||||||
|
<td>Férula de inmovilización</td>
|
||||||
|
<td>$8.000</td>
|
||||||
|
<td>$8.000</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class='totals-table'>
|
||||||
|
<tr>
|
||||||
|
<th>Subtotal</th>
|
||||||
|
<td>$18.000</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>IVA (21%)</th>
|
||||||
|
<td>$3.780</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Total</th>
|
||||||
|
<td><strong>$21.780</strong></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class='footer'>
|
||||||
|
Documento generado automáticamente por PhronCare - Solo para fines demostrativos. No válido como factura.
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>";
|
||||||
|
|
||||||
|
byte[] pdfBytes = await _pdfGeneratorService.GeneratePdfFromHtmlAsync(html);
|
||||||
|
|
||||||
|
return File(pdfBytes, "application/pdf", "Presupuesto.pdf");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,6 +15,8 @@ using Core.Services;
|
|||||||
using phronCare.API.Models.Security;
|
using phronCare.API.Models.Security;
|
||||||
using Models.Repositories;
|
using Models.Repositories;
|
||||||
using Models.Models;
|
using Models.Models;
|
||||||
|
using Transversal.Interfaces;
|
||||||
|
using Transversal.Services;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
@ -174,6 +176,9 @@ app.Run();
|
|||||||
|
|
||||||
static void RepositorysAndServices(WebApplicationBuilder builder)
|
static void RepositorysAndServices(WebApplicationBuilder builder)
|
||||||
{
|
{
|
||||||
|
// Registro servicio PDF transversal
|
||||||
|
builder.Services.AddScoped<IPdfGeneratorService, PuppeteerPdfGeneratorService>();
|
||||||
|
|
||||||
builder.Services.AddScoped<ITicketDom, TicketService>();
|
builder.Services.AddScoped<ITicketDom, TicketService>();
|
||||||
builder.Services.AddScoped<ITicketRepository, TicketRepository>();
|
builder.Services.AddScoped<ITicketRepository, TicketRepository>();
|
||||||
|
|
||||||
|
|||||||
@ -1056,6 +1056,16 @@
|
|||||||
],
|
],
|
||||||
"ReturnTypes": []
|
"ReturnTypes": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ContainingType": "phronCare.API.Controllers.PdfTestController",
|
||||||
|
"Method": "GetTestPdf",
|
||||||
|
"RelativePath": "api/PdfTest/test",
|
||||||
|
"HttpMethod": "GET",
|
||||||
|
"IsController": true,
|
||||||
|
"Order": 0,
|
||||||
|
"Parameters": [],
|
||||||
|
"ReturnTypes": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ContainingType": "phronCare.API.Controllers.Sales.PeopleController",
|
"ContainingType": "phronCare.API.Controllers.Sales.PeopleController",
|
||||||
"Method": "GetById",
|
"Method": "GetById",
|
||||||
|
|||||||
@ -501,7 +501,11 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"EPPlus": {
|
"EPPlus": {
|
||||||
"target": "Package",
|
"target": "Package",
|
||||||
"version": "[7.5.2, )"
|
"version": "[8.0.4, )"
|
||||||
|
},
|
||||||
|
"PuppeteerSharp": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[6.0.0, )"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"imports": [
|
"imports": [
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
<Import Project="$(NuGetPackageRoot)entityframework\6.5.1\buildTransitive\net6.0\EntityFramework.props" Condition="Exists('$(NuGetPackageRoot)entityframework\6.5.1\buildTransitive\net6.0\EntityFramework.props')" />
|
<Import Project="$(NuGetPackageRoot)entityframework\6.5.1\buildTransitive\net6.0\EntityFramework.props" Condition="Exists('$(NuGetPackageRoot)entityframework\6.5.1\buildTransitive\net6.0\EntityFramework.props')" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<PkgNewtonsoft_Json Condition=" '$(PkgNewtonsoft_Json)' == '' ">C:\Users\maski\.nuget\packages\newtonsoft.json\10.0.3</PkgNewtonsoft_Json>
|
||||||
<PkgMicrosoft_Extensions_ApiDescription_Server Condition=" '$(PkgMicrosoft_Extensions_ApiDescription_Server)' == '' ">C:\Users\maski\.nuget\packages\microsoft.extensions.apidescription.server\6.0.5</PkgMicrosoft_Extensions_ApiDescription_Server>
|
<PkgMicrosoft_Extensions_ApiDescription_Server Condition=" '$(PkgMicrosoft_Extensions_ApiDescription_Server)' == '' ">C:\Users\maski\.nuget\packages\microsoft.extensions.apidescription.server\6.0.5</PkgMicrosoft_Extensions_ApiDescription_Server>
|
||||||
<PkgMicrosoft_CodeAnalysis_Analyzers Condition=" '$(PkgMicrosoft_CodeAnalysis_Analyzers)' == '' ">C:\Users\maski\.nuget\packages\microsoft.codeanalysis.analyzers\3.3.3</PkgMicrosoft_CodeAnalysis_Analyzers>
|
<PkgMicrosoft_CodeAnalysis_Analyzers Condition=" '$(PkgMicrosoft_CodeAnalysis_Analyzers)' == '' ">C:\Users\maski\.nuget\packages\microsoft.codeanalysis.analyzers\3.3.3</PkgMicrosoft_CodeAnalysis_Analyzers>
|
||||||
<PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets Condition=" '$(PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets)' == '' ">C:\Users\maski\.nuget\packages\microsoft.visualstudio.azure.containers.tools.targets\1.21.0</PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets>
|
<PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets Condition=" '$(PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets)' == '' ">C:\Users\maski\.nuget\packages\microsoft.visualstudio.azure.containers.tools.targets\1.21.0</PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets>
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<Import Project="$(NuGetPackageRoot)system.text.json\8.0.5\buildTransitive\net6.0\System.Text.Json.targets" Condition="Exists('$(NuGetPackageRoot)system.text.json\8.0.5\buildTransitive\net6.0\System.Text.Json.targets')" />
|
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets')" />
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
|
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
|
||||||
|
<Import Project="$(NuGetPackageRoot)system.text.json\8.0.5\buildTransitive\net6.0\System.Text.Json.targets" Condition="Exists('$(NuGetPackageRoot)system.text.json\8.0.5\buildTransitive\net6.0\System.Text.Json.targets')" />
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server\6.0.5\build\Microsoft.Extensions.ApiDescription.Server.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server\6.0.5\build\Microsoft.Extensions.ApiDescription.Server.targets')" />
|
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server\6.0.5\build\Microsoft.Extensions.ApiDescription.Server.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server\6.0.5\build\Microsoft.Extensions.ApiDescription.Server.targets')" />
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.0\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.0\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets')" />
|
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.0\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.0\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets')" />
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets')" />
|
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.visualstudio.azure.containers.tools.targets\1.21.0\build\Microsoft.VisualStudio.Azure.Containers.Tools.Targets.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.visualstudio.azure.containers.tools.targets\1.21.0\build\Microsoft.VisualStudio.Azure.Containers.Tools.Targets.targets')" />
|
<Import Project="$(NuGetPackageRoot)microsoft.visualstudio.azure.containers.tools.targets\1.21.0\build\Microsoft.VisualStudio.Azure.Containers.Tools.Targets.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.visualstudio.azure.containers.tools.targets\1.21.0\build\Microsoft.VisualStudio.Azure.Containers.Tools.Targets.targets')" />
|
||||||
<Import Project="$(NuGetPackageRoot)entityframework\6.5.1\buildTransitive\net6.0\EntityFramework.targets" Condition="Exists('$(NuGetPackageRoot)entityframework\6.5.1\buildTransitive\net6.0\EntityFramework.targets')" />
|
<Import Project="$(NuGetPackageRoot)entityframework\6.5.1\buildTransitive\net6.0\EntityFramework.targets" Condition="Exists('$(NuGetPackageRoot)entityframework\6.5.1\buildTransitive\net6.0\EntityFramework.targets')" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,73 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.Reflection;
|
|
||||||
using Models.Models;
|
|
||||||
using Models.Repositories;
|
|
||||||
|
|
||||||
namespace phronCare.Test
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class TicketRepositoryTests
|
|
||||||
{
|
|
||||||
private TicketRepository _ticketRepository;
|
|
||||||
private PhronCareOperationsHubContext _context;
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
#if NETCOREAPP
|
|
||||||
// Copiar el archivo config para asegurarse de que ConfigurationManager lo encuentre
|
|
||||||
string configFile = $"{Assembly.GetExecutingAssembly().Location}.config";
|
|
||||||
string outputConfigFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
|
|
||||||
File.Copy(configFile, outputConfigFile, true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Obtener la cadena de conexión desde app.config usando ConfigurationManager
|
|
||||||
var connectionString = ConfigurationManager.ConnectionStrings["OperationsHub"]?.ConnectionString;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(connectionString))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("No se encontró la cadena de conexión 'OperationsHub'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var optionsBuilder = new DbContextOptionsBuilder<PhronCareOperationsHubContext>();
|
|
||||||
optionsBuilder.UseSqlServer(connectionString);
|
|
||||||
|
|
||||||
_context = new PhronCareOperationsHubContext(optionsBuilder.Options);
|
|
||||||
_ticketRepository = new TicketRepository(_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TearDown]
|
|
||||||
public void TearDown()
|
|
||||||
{
|
|
||||||
// Verifica que _context no sea null antes de llamarlo
|
|
||||||
_context?.Dispose();
|
|
||||||
}
|
|
||||||
[Test]
|
|
||||||
public async Task GetSummaryAsync_ShouldReturnValidSummaryData()
|
|
||||||
{
|
|
||||||
// Act
|
|
||||||
var summaryData = await _ticketRepository.GetSummaryAsync();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.That(summaryData, Is.Not.Null, "El resumen no debe ser nulo");
|
|
||||||
Assert.That(summaryData.Any(), Is.True, "El resumen debe contener al menos un elemento");
|
|
||||||
|
|
||||||
foreach (var item in summaryData)
|
|
||||||
{
|
|
||||||
Assert.Multiple(() =>
|
|
||||||
{
|
|
||||||
Assert.That(item.Estado, Is.Not.Null, "El campo Estado no debe ser nulo");
|
|
||||||
Assert.That(item.Cantidad, Is.GreaterThanOrEqualTo(0), "La cantidad debe ser mayor o igual a cero");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[Test]
|
|
||||||
public async Task GetAllAsync_ReturnsAllTickets()
|
|
||||||
{
|
|
||||||
var tickets = await _ticketRepository.GetAllAsync();
|
|
||||||
Assert.That(tickets, Is.Not.Null);
|
|
||||||
Assert.That(tickets.Any(), Is.True);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
142
phronCare.Test/PdfGeneratorServiceTests.cs
Normal file
142
phronCare.Test/PdfGeneratorServiceTests.cs
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
using Transversal.Services;
|
||||||
|
using Transversal.Models;
|
||||||
|
|
||||||
|
namespace phronCare.Test
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class PdfGeneratorServiceTests
|
||||||
|
{
|
||||||
|
private PuppeteerPdfGeneratorService _pdfService;
|
||||||
|
|
||||||
|
[OneTimeSetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
// Instancia real del servicio (recomendado para test manual/local)
|
||||||
|
_pdfService = new PuppeteerPdfGeneratorService();
|
||||||
|
}
|
||||||
|
|
||||||
|
[OneTimeTearDown]
|
||||||
|
public async Task TearDown()
|
||||||
|
{
|
||||||
|
// Liberar Chromium al finalizar los tests
|
||||||
|
if (_pdfService != null)
|
||||||
|
await _pdfService.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GeneratePdfFromHtml_ShouldCreatePdfFile()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
|
||||||
|
string html = @"
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; font-size: 12px; margin: 20px; }
|
||||||
|
.header { text-align: center; border-bottom: 2px solid #4CAF50; padding-bottom: 10px; margin-bottom: 20px; }
|
||||||
|
.header h1 { color: #4CAF50; }
|
||||||
|
.info { margin-bottom: 20px; }
|
||||||
|
.info table { width: 100%; }
|
||||||
|
.info td { padding: 5px; }
|
||||||
|
.details table { width: 100%; border-collapse: collapse; }
|
||||||
|
.details th, .details td { border: 1px solid #dddddd; text-align: center; padding: 8px; }
|
||||||
|
.details th { background-color: #4CAF50; color: white; }
|
||||||
|
.totals { margin-top: 20px; float: right; width: 300px; }
|
||||||
|
.totals table { width: 100%; border-collapse: collapse; }
|
||||||
|
.totals th, .totals td { border: 1px solid #dddddd; text-align: right; padding: 8px; }
|
||||||
|
.totals th { background-color: #4CAF50; color: white; }
|
||||||
|
.footer { position: fixed; bottom: 20px; left: 0; right: 0; text-align: center; font-size: 10px; color: gray; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class='header'>
|
||||||
|
<h1>PhronCare Ortopedia</h1>
|
||||||
|
<p>Presupuesto Médico</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='info'>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Cliente:</strong> Juan Pérez</td>
|
||||||
|
<td><strong>Presupuesto N°:</strong> 000123</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Fecha:</strong> 13/05/2025</td>
|
||||||
|
<td><strong>Profesional:</strong> Dr. Carlos López</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='details'>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Cantidad</th>
|
||||||
|
<th>Producto</th>
|
||||||
|
<th>Precio Unitario</th>
|
||||||
|
<th>Subtotal</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2</td>
|
||||||
|
<td>Rodillera ortopédica</td>
|
||||||
|
<td>$5.000</td>
|
||||||
|
<td>$10.000</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>1</td>
|
||||||
|
<td>Férula de inmovilización</td>
|
||||||
|
<td>$8.000</td>
|
||||||
|
<td>$8.000</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='totals'>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Subtotal</th>
|
||||||
|
<td>$18.000</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>IVA (21%)</th>
|
||||||
|
<td>$3.780</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Total</th>
|
||||||
|
<td><strong>$21.780</strong></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='footer'>
|
||||||
|
Presupuesto generado automáticamente por PhronCare - No válido como factura.
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>";
|
||||||
|
string outputFolder = @"C:\temp";
|
||||||
|
if (!Directory.Exists(outputFolder))
|
||||||
|
Directory.CreateDirectory(outputFolder);
|
||||||
|
|
||||||
|
string outputPath = Path.Combine(outputFolder, "DemoTest_Puppeteer.pdf");
|
||||||
|
|
||||||
|
// Opcional: podés probar pasando o no opciones
|
||||||
|
var options = new PdfGenerationOptions
|
||||||
|
{
|
||||||
|
Format = PuppeteerSharp.Media.PaperFormat.A4,
|
||||||
|
Landscape = false,
|
||||||
|
PrintBackground = true,
|
||||||
|
Scale = 1.0m,
|
||||||
|
HeaderTemplate = "<div style='font-size:10px; text-align:center;'>Presupuesto</div>",
|
||||||
|
FooterTemplate = "<div style='font-size:10px; text-align:center;'>Página <span class='pageNumber'></span> de <span class='totalPages'></span></div>"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
byte[] pdfBytes = await _pdfService.GeneratePdfFromHtmlAsync(html, options);
|
||||||
|
await File.WriteAllBytesAsync(outputPath, pdfBytes);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.IsTrue(File.Exists(outputPath));
|
||||||
|
Assert.IsTrue(new FileInfo(outputPath).Length > 0);
|
||||||
|
TestContext.WriteLine($"PDF generado correctamente en: {outputPath}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -31,7 +31,11 @@
|
|||||||
"frameworks": {
|
"frameworks": {
|
||||||
"net8.0": {
|
"net8.0": {
|
||||||
"targetAlias": "net8.0",
|
"targetAlias": "net8.0",
|
||||||
"projectReferences": {}
|
"projectReferences": {
|
||||||
|
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Transversal\\Transversal.csproj": {
|
||||||
|
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Transversal\\Transversal.csproj"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"warningProperties": {
|
"warningProperties": {
|
||||||
@ -98,6 +102,81 @@
|
|||||||
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.201/PortableRuntimeIdentifierGraph.json"
|
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.201/PortableRuntimeIdentifierGraph.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Transversal\\Transversal.csproj": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"restore": {
|
||||||
|
"projectUniqueName": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Transversal\\Transversal.csproj",
|
||||||
|
"projectName": "Transversal",
|
||||||
|
"projectPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Transversal\\Transversal.csproj",
|
||||||
|
"packagesPath": "C:\\Users\\maski\\.nuget\\packages\\",
|
||||||
|
"outputPath": "C:\\Users\\maski\\source\\repos\\SaludLAB\\phronCare\\Transversal\\obj\\",
|
||||||
|
"projectStyle": "PackageReference",
|
||||||
|
"fallbackFolders": [
|
||||||
|
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||||
|
],
|
||||||
|
"configFilePaths": [
|
||||||
|
"C:\\Users\\maski\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
|
||||||
|
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||||
|
],
|
||||||
|
"originalTargetFrameworks": [
|
||||||
|
"net8.0"
|
||||||
|
],
|
||||||
|
"sources": {
|
||||||
|
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||||
|
"https://api.nuget.org/v3/index.json": {}
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net8.0": {
|
||||||
|
"targetAlias": "net8.0",
|
||||||
|
"projectReferences": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warningProperties": {
|
||||||
|
"warnAsError": [
|
||||||
|
"NU1605"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"restoreAuditProperties": {
|
||||||
|
"enableAudit": "true",
|
||||||
|
"auditLevel": "low",
|
||||||
|
"auditMode": "direct"
|
||||||
|
},
|
||||||
|
"SdkAnalysisLevel": "9.0.200"
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"net8.0": {
|
||||||
|
"targetAlias": "net8.0",
|
||||||
|
"dependencies": {
|
||||||
|
"EPPlus": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[8.0.4, )"
|
||||||
|
},
|
||||||
|
"PuppeteerSharp": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[6.0.0, )"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"imports": [
|
||||||
|
"net461",
|
||||||
|
"net462",
|
||||||
|
"net47",
|
||||||
|
"net471",
|
||||||
|
"net472",
|
||||||
|
"net48",
|
||||||
|
"net481"
|
||||||
|
],
|
||||||
|
"assetTargetFallback": true,
|
||||||
|
"warn": true,
|
||||||
|
"frameworkReferences": {
|
||||||
|
"Microsoft.NETCore.App": {
|
||||||
|
"privateAssets": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.201/PortableRuntimeIdentifierGraph.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -21,7 +21,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!--<ProjectReference Include="..\Models\Models.csproj" />-->
|
<ProjectReference Include="..\Transversal\Transversal.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
46
phronCare.UIBlazor/Pages/Testpdf.razor
Normal file
46
phronCare.UIBlazor/Pages/Testpdf.razor
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
@page "/testpdf"
|
||||||
|
@inject HttpClient Http
|
||||||
|
@inject IJSRuntime JS
|
||||||
|
|
||||||
|
<h3>Visualizador PDF de prueba (servidor + local + descarga)</h3>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<button class="btn btn-primary me-2" @onclick="SavePdf">
|
||||||
|
<i class="fas fa-download me-1"></i> Guardar
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-success me-2" @onclick="ViewPdf">
|
||||||
|
<i class="fas fa-eye me-1"></i> Ver
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (!string.IsNullOrEmpty(LocalPdfPath))
|
||||||
|
{
|
||||||
|
<iframe src="@LocalPdfPath" width="100%" height="800px" style="border: 1px solid #ddd;"></iframe>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private string LocalPdfPath;
|
||||||
|
|
||||||
|
private async Task SavePdf()
|
||||||
|
{
|
||||||
|
string path = @"C:\temp\PresupuestoTest.pdf";
|
||||||
|
|
||||||
|
if (!Directory.Exists(@"C:\temp"))
|
||||||
|
Directory.CreateDirectory(@"C:\temp");
|
||||||
|
|
||||||
|
// ✅ 1. Llamar al endpoint de API para generar PDF
|
||||||
|
var pdfBytes = await Http.GetByteArrayAsync("http://localhost:5243/api/PdfTest/test"); // Cambia a tu URL real
|
||||||
|
|
||||||
|
// ✅ 2. Guardar en disco
|
||||||
|
System.IO.File.WriteAllBytes(path, pdfBytes);
|
||||||
|
|
||||||
|
// ✅ 3. Descargar al usuario
|
||||||
|
await JS.InvokeVoidAsync("saveAsFile", "PresupuestoTest.pdf", Convert.ToBase64String(pdfBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ViewPdf()
|
||||||
|
{
|
||||||
|
// 👉 Cargar el archivo guardado
|
||||||
|
LocalPdfPath = "/pdf/DemoTest.pdf";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,7 +12,6 @@ using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
|||||||
|
|
||||||
using Blazored.Modal;
|
using Blazored.Modal;
|
||||||
using Blazored.Toast;
|
using Blazored.Toast;
|
||||||
|
|
||||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||||
builder.RootComponents.Add<App>("#app");
|
builder.RootComponents.Add<App>("#app");
|
||||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
builder.RootComponents.Add<HeadOutlet>("head::after");
|
||||||
@ -48,7 +47,6 @@ static void InjectDependencies(WebAssemblyHostBuilder builder)
|
|||||||
builder.Services.AddScoped<ISalesLookupService, SalesLookupService>();
|
builder.Services.AddScoped<ISalesLookupService, SalesLookupService>();
|
||||||
builder.Services.AddScoped<IExchangeRateService, ExchangeRateService>();
|
builder.Services.AddScoped<IExchangeRateService, ExchangeRateService>();
|
||||||
|
|
||||||
|
|
||||||
builder.Services.AddScoped<ExchangeRateService>();
|
builder.Services.AddScoped<ExchangeRateService>();
|
||||||
builder.Services.AddScoped<QuoteService>();
|
builder.Services.AddScoped<QuoteService>();
|
||||||
builder.Services.AddScoped<TicketsService>();
|
builder.Services.AddScoped<TicketsService>();
|
||||||
@ -64,4 +62,5 @@ static void InjectDependencies(WebAssemblyHostBuilder builder)
|
|||||||
builder.Services.AddScoped<ProfessionalSpecialtyService>();
|
builder.Services.AddScoped<ProfessionalSpecialtyService>();
|
||||||
builder.Services.AddScoped<ProductCategoryService>();
|
builder.Services.AddScoped<ProductCategoryService>();
|
||||||
builder.Services.AddScoped<PatientService>();
|
builder.Services.AddScoped<PatientService>();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@
|
|||||||
{
|
{
|
||||||
<ul class="nav-flex-column">
|
<ul class="nav-flex-column">
|
||||||
<div class="nav-item px-1">
|
<div class="nav-item px-1">
|
||||||
<NavLink class="nav-link" href="sales/customers/">
|
<NavLink class="nav-link" href="Testpdf/">
|
||||||
<li aria-hidden="true"></li> Clientes
|
<li aria-hidden="true"></li> Clientes
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -239,7 +239,11 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"EPPlus": {
|
"EPPlus": {
|
||||||
"target": "Package",
|
"target": "Package",
|
||||||
"version": "[7.5.2, )"
|
"version": "[8.0.4, )"
|
||||||
|
},
|
||||||
|
"PuppeteerSharp": {
|
||||||
|
"target": "Package",
|
||||||
|
"version": "[6.0.0, )"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"imports": [
|
"imports": [
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
<Import Project="$(NuGetPackageRoot)blazored.modal\7.3.1\buildTransitive\Blazored.Modal.props" Condition="Exists('$(NuGetPackageRoot)blazored.modal\7.3.1\buildTransitive\Blazored.Modal.props')" />
|
<Import Project="$(NuGetPackageRoot)blazored.modal\7.3.1\buildTransitive\Blazored.Modal.props" Condition="Exists('$(NuGetPackageRoot)blazored.modal\7.3.1\buildTransitive\Blazored.Modal.props')" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
|
<PkgNewtonsoft_Json Condition=" '$(PkgNewtonsoft_Json)' == '' ">C:\Users\maski\.nuget\packages\newtonsoft.json\10.0.3</PkgNewtonsoft_Json>
|
||||||
<PkgMicrosoft_NET_Sdk_WebAssembly_Pack Condition=" '$(PkgMicrosoft_NET_Sdk_WebAssembly_Pack)' == '' ">C:\Users\maski\.nuget\packages\microsoft.net.sdk.webassembly.pack\9.0.3</PkgMicrosoft_NET_Sdk_WebAssembly_Pack>
|
<PkgMicrosoft_NET_Sdk_WebAssembly_Pack Condition=" '$(PkgMicrosoft_NET_Sdk_WebAssembly_Pack)' == '' ">C:\Users\maski\.nuget\packages\microsoft.net.sdk.webassembly.pack\9.0.3</PkgMicrosoft_NET_Sdk_WebAssembly_Pack>
|
||||||
<PkgMicrosoft_NET_ILLink_Tasks Condition=" '$(PkgMicrosoft_NET_ILLink_Tasks)' == '' ">C:\Users\maski\.nuget\packages\microsoft.net.illink.tasks\8.0.14</PkgMicrosoft_NET_ILLink_Tasks>
|
<PkgMicrosoft_NET_ILLink_Tasks Condition=" '$(PkgMicrosoft_NET_ILLink_Tasks)' == '' ">C:\Users\maski\.nuget\packages\microsoft.net.illink.tasks\8.0.14</PkgMicrosoft_NET_ILLink_Tasks>
|
||||||
<PkgMicrosoft_AspNetCore_Components_WebAssembly_DevServer Condition=" '$(PkgMicrosoft_AspNetCore_Components_WebAssembly_DevServer)' == '' ">C:\Users\maski\.nuget\packages\microsoft.aspnetcore.components.webassembly.devserver\8.0.6</PkgMicrosoft_AspNetCore_Components_WebAssembly_DevServer>
|
<PkgMicrosoft_AspNetCore_Components_WebAssembly_DevServer Condition=" '$(PkgMicrosoft_AspNetCore_Components_WebAssembly_DevServer)' == '' ">C:\Users\maski\.nuget\packages\microsoft.aspnetcore.components.webassembly.devserver\8.0.6</PkgMicrosoft_AspNetCore_Components_WebAssembly_DevServer>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.targets')" />
|
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets')" />
|
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\8.0.2\buildTransitive\net6.0\Microsoft.Extensions.Options.targets')" />
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.1\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.1\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
|
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.1\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\8.0.1\buildTransitive\net6.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
|
||||||
|
<Import Project="$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.sdk.webassembly.pack\9.0.3\build\Microsoft.NET.Sdk.WebAssembly.Pack.targets')" />
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.1\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.1\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets')" />
|
<Import Project="$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.1\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.configuration.binder\8.0.1\buildTransitive\netstandard2.0\Microsoft.Extensions.Configuration.Binder.targets')" />
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly.devserver\8.0.6\build\Microsoft.AspNetCore.Components.WebAssembly.DevServer.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly.devserver\8.0.6\build\Microsoft.AspNetCore.Components.WebAssembly.DevServer.targets')" />
|
<Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly.devserver\8.0.6\build\Microsoft.AspNetCore.Components.WebAssembly.DevServer.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.components.webassembly.devserver\8.0.6\build\Microsoft.AspNetCore.Components.WebAssembly.DevServer.targets')" />
|
||||||
<Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.components.analyzers\8.0.6\buildTransitive\netstandard2.0\Microsoft.AspNetCore.Components.Analyzers.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.components.analyzers\8.0.6\buildTransitive\netstandard2.0\Microsoft.AspNetCore.Components.Analyzers.targets')" />
|
<Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.components.analyzers\8.0.6\buildTransitive\netstandard2.0\Microsoft.AspNetCore.Components.Analyzers.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.components.analyzers\8.0.6\buildTransitive\netstandard2.0\Microsoft.AspNetCore.Components.Analyzers.targets')" />
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
BIN
phronCare.UIBlazor/wwwroot/pdf/DemoTest.pdf
Normal file
BIN
phronCare.UIBlazor/wwwroot/pdf/DemoTest.pdf
Normal file
Binary file not shown.
@ -1,27 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"date": "2022-01-06",
|
|
||||||
"temperatureC": 1,
|
|
||||||
"summary": "Freezing"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"date": "2022-01-07",
|
|
||||||
"temperatureC": 14,
|
|
||||||
"summary": "Bracing"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"date": "2022-01-08",
|
|
||||||
"temperatureC": -13,
|
|
||||||
"summary": "Freezing"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"date": "2022-01-09",
|
|
||||||
"temperatureC": -16,
|
|
||||||
"summary": "Balmy"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"date": "2022-01-10",
|
|
||||||
"temperatureC": -2,
|
|
||||||
"summary": "Chilly"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
Loading…
x
Reference in New Issue
Block a user