Add invoice provision-period PDF handling
Playwright Tests / test (push) Canceled after 0s

Normalize invoice provision periods in PDF generation, switch admin labels between single-date and range modes, add end-to-end tests, update package and frontend bundle versions, and note the invoice lifecycle docs update.
This commit is contained in:
Stefan
2026-10-09 12:03:06 +02:00
parent 4443bba63c
commit 24b94b05c2
5 changed files with 109 additions and 6 deletions
+3 -1
View File
@@ -97,7 +97,9 @@ payload; see `EVAL_live_invoice_editing.md` for the rationale.
it drives the EN 16931 eRechnung and composes the free-text `SendToAddress` for the
PDF (see [`Concepts/erechnung-output.md`](Concepts/erechnung-output.md)). The **service
date/period** (Leistungsdatum/-zeitraum) is likewise a structured German-date dialog
(`$inv.eProvisionPeriod`) — a single date or a from/to range — mapped to BT-72 / BG-14.
(`$inv.eProvisionPeriod`) — a single date or a from/to range — mapped to BT-72 / BG-14
and printed in the PDF's admin block (`InvoiceService.ApplyProvisionPeriod`; legacy ISO
values are shown as German dates).
- **§13b reverse-charge** toggle (`$inv.sp13b`) — suppresses VAT lines/columns.
- **Set-pricing display mode** (`$inv.ssetmode` / `setSetmode`) — `SetPrice`
(default) / `SetOnly`; see `INVOICE_SET_PRICING.md`. Purely presentational
+2 -2
View File
@@ -51,10 +51,10 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<!-- New packages (needed for .NET 10) -->
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.1.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="4.1.2" />
<PackageReference Include="SixLabors.ImageSharp" Version="4.1.3" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="10.0.12" />
<PackageReference Include="System.Drawing.Common" Version="10.0.12" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.30.0" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.30.1" />
</ItemGroup>
<ItemGroup>
<Folder Include="App_Data\cache\" />
+17
View File
@@ -320,6 +320,22 @@ public class InvoiceService : IInvoiceService
}
}
/// <summary>
/// Puts the stored Leistungsdatum / -zeitraum into the PDF admin block: German dates (legacy ISO
/// values converted) and the label the editor shows — "Leistungsdatum" for one date,
/// "Leistungszeitraum" for a from–to range.
/// </summary>
internal static void ApplyProvisionPeriod(FuchsPdf.FdsTextBlocks tb, string? provisionPeriod)
{
tb.ProvisionPeriod = ProvisionPeriodForDisplay(provisionPeriod).Trim();
tb.AdminProvLabel = tb.ProvisionPeriod.Contains(" - ") || tb.ProvisionPeriod.Length == 0
? "Leistungszeitraum" : "Leistungsdatum";
}
/// <summary>Shows ISO dates (yyyy-MM-dd) saved by older editor versions as German dd.MM.yyyy.</summary>
internal static string ProvisionPeriodForDisplay(string? period) =>
System.Text.RegularExpressions.Regex.Replace(period ?? "", @"\b(\d{4})-(\d{2})-(\d{2})\b", "$3.$2.$1");
public async Task<Document> GenerateInvoicePdfAsync(FdsInvoiceData invoice, bool draft)
{
using var act = FuchsTelemetry.StartActivity("invoice.render");
@@ -339,6 +355,7 @@ public class InvoiceService : IInvoiceService
// e-invoice issue date (ERechnungMapper), see InvoiceDates / ADR 0032.
AdminDatumValue = InvoiceDates.IssueDate(reg).ToDateTime(TimeOnly.MinValue)
};
ApplyProvisionPeriod(tb, reg?.getString("ProvisionPeriod"));
var inlineImages = await ResolveInlineImagesAsync(invoice);
var doc = await _pdf.WriteLetterAsync(tb, draft);
doc.Info.Title = reg?.getString("InvoiceTitle") ?? "";
File diff suppressed because one or more lines are too long