diff --git a/src/Yavsc.Api/Controllers/Business/FrontOfficeApiController.cs b/src/Yavsc.Api/Controllers/Business/FrontOfficeApiController.cs index 56c7a1f51..71ceca3d5 100644 --- a/src/Yavsc.Api/Controllers/Business/FrontOfficeApiController.cs +++ b/src/Yavsc.Api/Controllers/Business/FrontOfficeApiController.cs @@ -23,7 +23,7 @@ namespace Yavsc.ApiControllers private readonly IBillingService billing; private readonly ILogger logger; private readonly SiteSettings siteSettings; - private readonly IViewEngine viewEngine; + private readonly IRazorViewEngine viewEngine; // The view-rendering dependencies (siteSettings, viewEngine) are // optional: only EstimateTex/EstimatePdf use them, and those run in @@ -51,7 +51,7 @@ namespace Yavsc.ApiControllers this.billing = billing ?? new BillingService(context); logger = loggerFactory.CreateLogger(); this.siteSettings = siteSettings?.Value; - this.viewEngine = viewEngine as IViewEngine; + this.viewEngine = viewEngine; } [HttpGet("profiles/{actCode}")] @@ -97,9 +97,14 @@ namespace Yavsc.ApiControllers public async Task EstimatePdf(long queryId, CancellationToken token) { if (viewEngine is null || siteSettings is null) - return Problem("PDF rendering is not configured on this host.", + { + string msg = "PDF rendering is not configured on this host."; + logger.LogError(msg); + return Problem(msg, statusCode: StatusCodes.Status503ServiceUnavailable); + } + var estimate = await LoadEstimateForRenderAsync(queryId, token); if (estimate is null) return NotFound(new { Error = "no estimate linked to this query" }); @@ -135,22 +140,21 @@ namespace Yavsc.ApiControllers // we stream the generated PDF bytes — but driving the // generation through the view keeps the template as the // output producer, per the original design. - this.RenderViewToString(viewEngine, "Estimate_pdf", model); + if (model.GenerateEstimatePdf() is FileInfo fo) + { + return File(fo.OpenRead(), "application/pdf"); + } + string msg = "TeX render failed: " + model.GenerationErrorMessage; + logger.LogError(msg); + return Problem(msg); + } catch (Exception ex) { logger.LogError(ex, "estimate {QueryId}: TeX/PDF render failed", queryId); return Problem("TeX render failed: " + ex.Message); } - - if (!model.Generated) - return Problem("PDF generation failed: " - + (model.GenerationErrorMessage?.Value ?? "unknown error")); - - var pdfPath = System.IO.Path.Combine(billsDir, baseFileName + ".pdf"); - var bytes = await System.IO.File.ReadAllBytesAsync(pdfPath, token); - return File(bytes, "application/pdf", baseFileName + ".pdf"); - } + } // Loads the estimate linked to a query with the navigation the // Estimate_tex template reads (client + performer profile + bill). @@ -402,4 +406,4 @@ namespace Yavsc.ViewModels.FrontOffice /// public SignatureType? SignatureType { get; set; } } -} \ No newline at end of file +} diff --git a/src/Yavsc.Api/Helpers/TeXHelpers.cs b/src/Yavsc.Api/Helpers/TeXHelpers.cs index 151ad727f..a36e23e64 100644 --- a/src/Yavsc.Api/Helpers/TeXHelpers.cs +++ b/src/Yavsc.Api/Helpers/TeXHelpers.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.ViewFeatures; namespace Yavsc.Helpers { + using Microsoft.AspNetCore.Mvc.Razor; using ViewModels.Gen; public class TeXString : HtmlString { @@ -115,7 +116,7 @@ namespace Yavsc.Helpers return new TeXString(string.Join(lineSeparator,texlines)); } - public static bool GenerateEstimatePdf(this SiteSettings settings, PdfGenerationViewModel Model) + public static FileInfo GenerateEstimatePdf(this PdfGenerationViewModel Model) { string errorMsg = null; // Resolve to an absolute path: SiteSettings.Bills may be a @@ -195,17 +196,18 @@ namespace Yavsc.Helpers ".fdb_latexmk", ".synctex.gz", ".toc" }) { if (ext == ".log" && !fo.Exists) continue; - var f = new FileInfo(System.IO.Path.Combine(billdir, name + ext)); + var fileName = name + ext; + var f = new FileInfo(System.IO.Path.Combine(billdir, fileName)); if (f.Exists) { try { f.Delete(); } catch { } } } Model.Generated = fo.Exists; Model.GenerationErrorMessage = new HtmlString(errorMsg); - return fo.Exists; + return fo; } public static string RenderViewToString( - this Controller controller, IViewEngine engine, + this Controller controller, IRazorViewEngine engine, string viewName, object model, bool isMainPage = true) { if (engine == null) diff --git a/src/Yavsc.Api/ViewComponents/BillViewComponent.cs b/src/Yavsc.Api/ViewComponents/BillViewComponent.cs deleted file mode 100644 index 0217ebcf2..000000000 --- a/src/Yavsc.Api/ViewComponents/BillViewComponent.cs +++ /dev/null @@ -1,108 +0,0 @@ - -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Localization; -using Yavsc.Billing; -using Yavsc.Helpers; -using Yavsc.Models; -using Yavsc.ViewModels; -using Yavsc.ViewModels.Gen; -using Yavsc.Services; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Options; - -namespace Yavsc.ViewComponents -{ - public class BillViewComponent : ViewComponent - { - readonly ApplicationDbContext dbContext; - readonly IBillingService billing; - readonly IStringLocalizer localizer; - private readonly SiteSettings siteSettings; - - public BillViewComponent(ApplicationDbContext dbContext, - IStringLocalizer localizer, - IBillingService billing, - IOptions siteSettings) - { - this.billing = billing; - this.dbContext = dbContext; - this.localizer = localizer; - this.siteSettings = siteSettings.Value; - } - - public async Task InvokeAsync( - string code, - IBillable billable, - OutputFormat format, - bool asBill, - SiteSettings settings - ) - { - var di = new DirectoryInfo(settings.Bills); - var dia = new DirectoryInfo(settings.Avatars); - ViewBag.BillsDir = di.FullName; - ViewBag.AvatarsDir = dia.FullName; - ViewBag.AsBill = asBill; // vrai pour une facture, sinon, c'est un devis - ViewBag.Acquitted = billable.GetIsAcquitted(); - - ViewBag.BillingCode = code; - var client = await dbContext.Users - .Include(u=>u.PostalAddress) - .SingleAsync(u=>u.Id == billable.ClientId); - ViewBag.Client = client; - var performer = await dbContext.Users - .Include(u=>u.BankInfo) - .Include(u=>u.PostalAddress) - .SingleAsync(u=>u.Id == billable.PerformerId); - ViewBag.Performer = performer; - string clientAddress = client.PostalAddress?.Address ?? null; - ViewBag.ClientAddress = clientAddress.SplitAddressToTeX(); - - - var profile = await dbContext.Performers - .Include(p=>p.OrganizationAddress) - .SingleAsync(p=>p.PerformerId == billable.PerformerId); - ViewBag.PerformerProfile = profile; - ViewBag.ActivityLabel = (await dbContext.Activities.SingleAsync(a => a.Code == billable.ActivityCode)).Name; - - var proAddr = profile.OrganizationAddress.Address; - ViewBag.PerformerOrganizationAddress = proAddr.SplitAddressToTeX() ; - ViewBag.FooterPerformerOrganizationAddress = proAddr.SplitAddressToTeX(", "); - - ViewBag.PerformerAddress = performer.PostalAddress?.Address.SplitAddressToTeX() ; - switch (format) { - case OutputFormat.LaTeX : - return this.View("Bill_tex", billable); - case OutputFormat.Pdf : - string tex = null; - var oldWriter = ViewComponentContext.ViewContext.Writer; - using (var writer = new StringWriter()) - { - this.ViewComponentContext.ViewContext.Writer = writer; - var resultTex = View("Bill_tex", billable); - await resultTex.ExecuteAsync(this.ViewComponentContext); - tex = writer.ToString(); - } - ViewComponentContext.ViewContext.Writer = oldWriter; - - var pdfGenerationViewModel = new PdfGenerationViewModel - { - Temp = siteSettings.TempDir, - TeXSource = tex, - DestDir = siteSettings.Bills, - BaseFileName = billable.GetFileBaseName(billing) - }; - if (settings.GenerateEstimatePdf(pdfGenerationViewModel)) { - return this.View(new { Generated = pdfGenerationViewModel.BaseFileName+".pdf" }); - } else { - return View(new { Error = pdfGenerationViewModel.GenerationErrorMessage } ); - } - } - ViewBag.BillFileInfo = billable.GetBillInfo(billing, siteSettings); - ViewBag.Settings = settings; - return View("Default",billable); - - } - - } -} diff --git a/src/Yavsc.Api/ViewModels/Gen/PdfGenerationViewModel.cs b/src/Yavsc.Api/ViewModels/Gen/PdfGenerationViewModel.cs index fe934e3ac..841e8d5dd 100644 --- a/src/Yavsc.Api/ViewModels/Gen/PdfGenerationViewModel.cs +++ b/src/Yavsc.Api/ViewModels/Gen/PdfGenerationViewModel.cs @@ -5,7 +5,7 @@ namespace Yavsc.ViewModels.Gen { public class PdfGenerationViewModel { - + [Required] public string TeXSource { get; set; } [Required] diff --git a/src/Yavsc.Api/Views/Shared/Components/Bill/Bill_tex.cshtml b/src/Yavsc.Api/Views/Shared/Bill_tex.cshtml similarity index 100% rename from src/Yavsc.Api/Views/Shared/Components/Bill/Bill_tex.cshtml rename to src/Yavsc.Api/Views/Shared/Bill_tex.cshtml diff --git a/src/Yavsc.Api/Views/Shared/Components/Bill/Bill_pdf.cshtml b/src/Yavsc.Api/Views/Shared/Components/Bill/Bill_pdf.cshtml deleted file mode 100644 index f49fad802..000000000 --- a/src/Yavsc.Api/Views/Shared/Components/Bill/Bill_pdf.cshtml +++ /dev/null @@ -1,21 +0,0 @@ -@using System.Reflection -@using System.IO -@using Microsoft.Extensions.WebEncoders -@using System.Diagnostics -@using System.Text -@using Yavsc.Helpers -@model Yavsc.ViewModels.Gen.PdfGenerationViewModel - -@{ - ViewBag.Settings.GenerateEstimatePdf(Model); -} -@if (Model.Generated) { -
- @(Model.BaseFileName).pdf was generated -
-} else { -
- @Model.GenerationErrorMessage -

Something went wrong ...

-
-} diff --git a/src/Yavsc.Api/Views/Shared/Components/Bill/Default.cshtml b/src/Yavsc.Api/Views/Shared/Components/Bill/Default.cshtml deleted file mode 100644 index f2d0e0163..000000000 --- a/src/Yavsc.Api/Views/Shared/Components/Bill/Default.cshtml +++ /dev/null @@ -1,33 +0,0 @@ - -@model IBillable -
-@if (ViewBag.BillFileInfo.Exists) { -La facture au format Pdf -} else { - -
-
- - -
-
-
-
-} -
diff --git a/src/Yavsc.Api/Views/Shared/Estimate_pdf.cshtml b/src/Yavsc.Api/Views/Shared/Estimate_pdf.cshtml deleted file mode 100644 index bef19b35a..000000000 --- a/src/Yavsc.Api/Views/Shared/Estimate_pdf.cshtml +++ /dev/null @@ -1,21 +0,0 @@ -@using System.Reflection -@using System.IO -@using Microsoft.Extensions.WebEncoders -@using System.Diagnostics -@using System.Text -@using Yavsc.Helpers -@model Yavsc.ViewModels.Gen.PdfGenerationViewModel - -@{ - SiteSettings.Value.GenerateEstimatePdf(Model); -} -@if (Model.Generated) { -
- @(Model.BaseFileName).pdf was generated -
-} else { -
- @Model.GenerationErrorMessage -

Something went wrong ...

-
-} diff --git a/src/Yavsc.Api/Views/Shared/Estimate_tex.cshtml b/src/Yavsc.Api/Views/Shared/Estimate_tex.cshtml index 5048f1149..1209ce3b6 100644 --- a/src/Yavsc.Api/Views/Shared/Estimate_tex.cshtml +++ b/src/Yavsc.Api/Views/Shared/Estimate_tex.cshtml @@ -49,7 +49,7 @@ \global\let\TotalHT\TotalHT \global\let\TotalTVA\TotalTVA \global\let\TotalTTC\TotalTTC - \cr + \cr \hline \textbf{Total} & & & \TotalHT } @@ -77,12 +77,12 @@ % Infos Client \def\ClientNom{@TeXHelpers.ToTeX(to.UserName)} % Nom du client -\def\ClientAdresse{ +\def\ClientAdresse{ % Adresse du client @PostalAddress @if (PostalAddress!=null) {@PostalAddress} @if (!string.IsNullOrWhiteSpace(to.PhoneNumber)) {@TeXHelpers.ToTeX(to.PhoneNumber)\\ - } + } E-mail: @TeXHelpers.ToTeX(to.Email) } @@ -105,7 +105,7 @@ \renewcommand{\headrulewidth}{0pt} \cfoot{ @TeXHelpers.ToTeX(from.UserName) @if (proaddrm!=null) { - @proaddrm } \newline - \small{ E-mail: @TeXHelpers.ToTeX(from.Email) @if (!string.IsNullOrWhiteSpace(from.PhoneNumber)) { - Téléphone fixe: @TeXHelpers.ToTeX(from.PhoneNumber) } + \small{ E-mail: @TeXHelpers.ToTeX(from.Email) @if (!string.IsNullOrWhiteSpace(from.PhoneNumber)) { - Téléphone fixe: @TeXHelpers.ToTeX(from.PhoneNumber) } } } @@ -113,10 +113,10 @@ % Logo de la société @if (from.Avatar != null) { -\includegraphics[height=60pt]{@(ViewBag.AvatarsDir)/@(from.UserName).png} +\includegraphics[height=60pt, viewport=0 0 128 128]{@(ViewBag.AvatarsDir)/@(from.UserName).png} -} else { -%\includegraphics{logo.png} +} else { +%\includegraphics[height=60pt, viewport=0 0 128 128]{logo.png} } % Nom et adresse de la société @@ -170,12 +170,12 @@ \begin{center} \begin{tabular}{|c c c c|} @if (!string.IsNullOrWhiteSpace(bi.BankCode) && !string.IsNullOrWhiteSpace(bi.WicketCode) - && !string.IsNullOrWhiteSpace(bi.AccountNumber) ) { + && !string.IsNullOrWhiteSpace(bi.AccountNumber) ) { \hline \textbf{Code banque} & \textbf{Code guichet} & \textbf{N° de Compte} & \textbf{Clé RIB} \\ @bi.BankCode & @bi.WicketCode & @bi.AccountNumber & @bi.BankedKey \\ } - @if (!string.IsNullOrWhiteSpace(@bi.IBAN) && !string.IsNullOrWhiteSpace(@bi.BIC)) { + @if (!string.IsNullOrWhiteSpace(@bi.IBAN) && !string.IsNullOrWhiteSpace(@bi.BIC)) { \hline \textbf{IBAN N°} & \multicolumn{3}{|l|}{ @bi.IBAN } \\ \hline \textbf{Code BIC} & \multicolumn{3}{|l|}{ @bi.BIC }