phronCare/Documents/Services/DocumentTemplateService.cs

102 lines
3.7 KiB
C#
Raw Normal View History

2025-09-04 18:15:15 -03:00
using System.Collections.Concurrent;
using Documents.Interfaces;
2025-05-15 19:24:12 -03:00
using Documents.Models;
2025-09-04 18:15:15 -03:00
using Domain.Dtos; // QuoteDto
using Domain.Dtos.Sales; // DeliveryNoteDto
2025-09-04 18:15:15 -03:00
using Domain.Dtos.Stock; // ExpeditionDto
2025-05-15 19:24:12 -03:00
using Transversal.Interfaces;
2025-05-16 19:20:31 -03:00
public class DocumentTemplateService : IDocumentTemplateService
2025-05-15 19:24:12 -03:00
{
2025-05-16 19:20:31 -03:00
private readonly ITemplateRenderer _templateRenderer;
private readonly IPdfGeneratorService _pdfGeneratorService;
2025-09-04 18:15:15 -03:00
// Cache simple para no leer el logo del disco en cada render
private static readonly ConcurrentDictionary<string, string> _imageCacheBase64 = new();
2025-05-16 19:20:31 -03:00
public DocumentTemplateService(ITemplateRenderer templateRenderer, IPdfGeneratorService pdfGeneratorService)
2025-05-15 19:24:12 -03:00
{
2025-05-16 19:20:31 -03:00
_templateRenderer = templateRenderer;
_pdfGeneratorService = pdfGeneratorService;
}
2025-05-15 19:24:12 -03:00
2025-05-16 19:20:31 -03:00
public async Task<byte[]> GenerateDocumentAsync(DocumentGenerationRequest request)
{
2025-09-04 18:15:15 -03:00
if (request is null) throw new ArgumentNullException(nameof(request));
if (request.Model is null) throw new ArgumentNullException(nameof(request.Model));
2025-07-15 16:51:29 -03:00
2025-09-04 18:15:15 -03:00
string? templatePath = null;
2025-05-15 19:24:12 -03:00
2025-09-04 18:15:15 -03:00
try
2025-05-15 19:24:12 -03:00
{
2025-09-04 18:15:15 -03:00
// 1) Elegir plantilla por tipo de documento
templatePath = ResolveTemplate(request.DocumentType);
// 2) Inyectar logo (si el DTO lo soporta)
var logoBase64 = GetImageBase64Cached(
Path.Combine(Directory.GetCurrentDirectory(), "Resources", "logo.png"));
InjectLogoIfSupported(request.Model, logoBase64);
// 3) Render + PDF
var html = await _templateRenderer.RenderAsync(templatePath, request.Model);
return await _pdfGeneratorService.GeneratePdfFromHtmlAsync(html);
2025-05-15 19:24:12 -03:00
}
2025-09-04 18:15:15 -03:00
catch (Exception ex)
{
// Envolvemos con contexto para facilitar el diagnóstico
var wrapped = new Exception(
$"Document generation failed (DocumentType={request.DocumentType}, Template='{templatePath ?? "?"}', ModelType={request.Model.GetType().FullName}). See inner exception.",
ex
);
wrapped.Data["DocumentType"] = request.DocumentType.ToString();
if (!string.IsNullOrEmpty(templatePath)) wrapped.Data["TemplatePath"] = templatePath;
wrapped.Data["ModelType"] = request.Model.GetType().FullName;
throw wrapped;
}
}
private static string ResolveTemplate(DocumentType type) => type switch
{
DocumentType.Quote => "Quotes/Template_v1.cshtml",
DocumentType.DeliveryNote => "DeliveryNotes/Template_v1.cshtml",
2025-09-04 18:15:15 -03:00
DocumentType.Expedition => "Expeditions/Template_v1.cshtml",
_ => "Shared/Template_Generic.cshtml"
};
2025-05-15 19:24:12 -03:00
2025-09-04 18:15:15 -03:00
private static void InjectLogoIfSupported(object model, string base64)
{
// Inyección “segura”: si el modelo expone LogoBase64, lo seteamos.
switch (model)
{
case QuoteDto q:
q.LogoBase64 = base64;
break;
case ExpeditionDto e:
e.LogoBase64 = base64;
break;
case DeliveryNoteDto d:
d.LogoBase64 = base64;
break;
2025-09-04 18:15:15 -03:00
default:
// Si no tiene LogoBase64, no hacemos nada.
break;
}
2025-05-16 19:20:31 -03:00
}
2025-09-04 18:15:15 -03:00
private static string GetImageBase64Cached(string imagePath)
2025-05-16 19:20:31 -03:00
{
2025-09-04 18:15:15 -03:00
if (_imageCacheBase64.TryGetValue(imagePath, out var cached))
return cached;
2025-05-16 19:20:31 -03:00
if (!File.Exists(imagePath))
2025-09-04 18:15:15 -03:00
{
_imageCacheBase64[imagePath] = "";
2025-05-16 19:20:31 -03:00
return "";
2025-09-04 18:15:15 -03:00
}
2025-05-16 19:20:31 -03:00
2025-09-04 18:15:15 -03:00
var base64 = Convert.ToBase64String(File.ReadAllBytes(imagePath));
_imageCacheBase64[imagePath] = base64;
return base64;
2025-05-15 19:24:12 -03:00
}
}