using General_Ledger_Service.DTOs.Reports; using QuestPDF.Fluent; using QuestPDF.Helpers; using QuestPDF.Infrastructure; namespace General_Ledger_Service.Services.PdfDocuments { // 05_LKAS_Report_PDF_Templates.md Section 5 (LKAS 7, full statement). Retrofit 2026-07-22: // no printed opening/closing cash balance (still in the Json/Csv data for the reconciliation // check, just not displayed here, matching the reference template); nonCashAdjustments and // workingCapitalChanges are combined and re-bucketed by sign at render time into "Additions // to Cash"/"Subtractions From Cash" rather than kept as two separate lists. Working-capital // lines now use the account's own Direction ("Increase"/"Decrease") for their wording, since // that's no longer derivable from ChangeAmount's sign alone (see the DTO's comment). public class CashFlowPdfDocument(string companyName, string currencyCode, CashFlowReportDto data) : IDocument { private record CashMovementLine(string Description, decimal Amount); public DocumentMetadata GetMetadata() => DocumentMetadata.Default; public void Compose(IDocumentContainer container) { var operating = data.OperatingActivities; var operatingProfitBeforeWorkingCapital = operating.ProfitForPeriod + operating.NonCashAdjustments.Sum(a => a.Amount); var movements = operating.NonCashAdjustments .Select(a => new CashMovementLine(a.Description, a.Amount)) .Concat(operating.WorkingCapitalChanges.Select(c => new CashMovementLine($"{c.Direction} in {c.AccountName}", c.ChangeAmount))) .ToList(); var additions = movements.Where(m => m.Amount > 0).ToList(); var subtractions = movements.Where(m => m.Amount <= 0).ToList(); container.Page(page => { page.Size(PageSizes.A4); page.Margin(2, Unit.Centimetre); ReportPageHeader.Compose(page, companyName, "Statement of Cash Flows", ReportPageHeader.RangePeriodLine(data.PeriodStart, data.PeriodEnd), currencyCode); page.Content().PaddingTop(10).Column(column => { column.Item().Text("Cash Flows from Operating Activities").Bold(); column.Item().Row(r => { r.RelativeItem(4).Text("Profit for the period"); r.RelativeItem(1).AlignRight().Text(PdfFormatting.FormatAmount(operating.ProfitForPeriod)); }); column.Item().Row(r => { r.RelativeItem(4).Text("Operating profit before working capital changes"); r.RelativeItem(1).AlignRight().Text(PdfFormatting.FormatAmount(operatingProfitBeforeWorkingCapital)); }); if (additions.Count > 0) { column.Item().PaddingTop(5).Text("Additions to Cash"); foreach (var line in additions) { column.Item().PaddingLeft(10).Row(r => { r.RelativeItem(4).Text(line.Description); r.RelativeItem(1).AlignRight().Text(PdfFormatting.FormatAmount(line.Amount)); }); } } if (subtractions.Count > 0) { column.Item().PaddingTop(5).Text("Subtractions From Cash"); foreach (var line in subtractions) { column.Item().PaddingLeft(10).Row(r => { r.RelativeItem(4).Text(line.Description); r.RelativeItem(1).AlignRight().Text(PdfFormatting.FormatAmount(line.Amount)); }); } } column.Item().PaddingTop(3).LineHorizontal(1); column.Item().Row(r => { r.RelativeItem(4).Text("Net Cash from Operating Activities").Bold(); r.RelativeItem(1).AlignRight().Text(PdfFormatting.FormatAmount(operating.NetCashFromOperatingActivities)).Bold(); }); column.Item().PaddingTop(15).Text("Cash Flows from Investing Activities").Bold(); foreach (var line in data.InvestingActivities.Lines) { column.Item().Row(r => { r.RelativeItem(4).Text(line.AccountName); r.RelativeItem(1).AlignRight().Text(PdfFormatting.FormatAmount(line.Amount)); }); } column.Item().PaddingTop(3).LineHorizontal(1); column.Item().Row(r => { var label = data.InvestingActivities.NetCashFromInvestingActivities < 0 ? "Net Cash used in Investing Activities" : "Net Cash from Investing Activities"; r.RelativeItem(4).Text(label).Bold(); r.RelativeItem(1).AlignRight().Text(PdfFormatting.FormatAmount(data.InvestingActivities.NetCashFromInvestingActivities)).Bold(); }); column.Item().PaddingTop(15).Text("Cash Flows from Financing Activities").Bold(); foreach (var line in data.FinancingActivities.Lines) { column.Item().Row(r => { r.RelativeItem(4).Text(line.AccountName); r.RelativeItem(1).AlignRight().Text(PdfFormatting.FormatAmount(line.Amount)); }); } column.Item().PaddingTop(3).LineHorizontal(1); column.Item().Row(r => { var label = data.FinancingActivities.NetCashFromFinancingActivities < 0 ? "Net Cash used in Financing Activities" : "Net Cash from Financing Activities"; r.RelativeItem(4).Text(label).Bold(); r.RelativeItem(1).AlignRight().Text(PdfFormatting.FormatAmount(data.FinancingActivities.NetCashFromFinancingActivities)).Bold(); }); column.Item().PaddingTop(15).LineHorizontal(1.5f); column.Item().Row(r => { var label = data.NetIncreaseDecreaseInCash < 0 ? "Net Decrease in Cash and Cash Equivalents" : "Net Increase in Cash and Cash Equivalents"; r.RelativeItem(4).Text(label).Bold(); r.RelativeItem(1).AlignRight().Text(PdfFormatting.FormatAmount(data.NetIncreaseDecreaseInCash)).Bold(); }); }); }); } } }