using System.Globalization; using System.Net.Mime; using QuestPDF.Fluent; using QuestPDF.Helpers; using QuestPDF.Infrastructure; namespace Server.Model { public class InvoiceDocument(InvoiceModel model) : IDocument { private InvoiceModel Model { get; } = model; public void Compose(IDocumentContainer container) { container.Page(page => { page.Size(PageSizes.A4); page.Margin(10, Unit.Millimetre); page.MarginLeft(20, Unit.Millimetre); page.PageColor(Colors.White); page.DefaultTextStyle(x => x.FontSize(12).FontFamily(Fonts.Calibri).Light()); page.Header().Element(ComposeHeader); page.Content().Element(ComposeContent); page.Footer().Element(ComposeFooter); }); } private void ComposeContent(IContainer container) { container.PaddingVertical(40).Column(column => { column.Spacing(5); column.Item().Element(ComposeTable); if (!string.IsNullOrWhiteSpace(Model.Comment)) column.Item().PaddingTop(25).Element(ComposeComments); }); } private void ComposeTable(IContainer container) { container.Table(table => { // Define columns table.ColumnsDefinition(columns => { columns.ConstantColumn(30, Unit.Millimetre); columns.RelativeColumn(3); columns.RelativeColumn(); columns.RelativeColumn(); }); // Describe header table.Header(header => { header.Cell().Element(CellStyle).AlignCenter().Text("Menge"); header.Cell().Element(CellStyle).Text("Bezeichnung"); header.Cell().Element(CellStyle).AlignRight().Text("Einzelpreis"); header.Cell().Element(CellStyle).AlignRight().Text("Gesamtpreis"); static IContainer CellStyle(IContainer container) { return container.DefaultTextStyle(x => x.SemiBold()).BorderBottom(1).BorderColor(Colors.Black); } }); // Describe content foreach (var item in Model.Items ?? []) { table.Cell().Element(CellStyle).AlignCenter().Text(txt => txt.Span($"{item.Quantity:N2}")); table.Cell().Element(CellStyle).Column(column => { column.Item().Text(item.Name); if(!string.IsNullOrWhiteSpace(item.Description)) column.Item().Text(txt => { txt.Span(item.Description).FontSize(8); }); }); // string as currency format table.Cell().Element(CellStyle).AlignRight().Text($"{item.PriceNetto:N2} €"); table.Cell().Element(CellStyle).AlignRight().Text($"{item.PriceNetto * item.Quantity:N2} €"); continue; } // Gesamt Netto table.Cell().ColumnSpan(3).PaddingTop(10).Text("Gesamt Netto"); table.Cell().PaddingTop(10).AlignRight().Text($"{Model.TotalNetto:N2} €"); // 7% var tax7Items = Model.Items?.Where(x => x.TaxType == TaxType.Tax7).ToList() ?? []; if (tax7Items.Count > 0) { var tax7Netto = tax7Items.Sum(x => x.PriceNetto * x.Quantity); var tax7Tax = tax7Netto * 0.07; table.Cell().ColumnSpan(2).Text("zzgl. 7% USt. auf"); table.Cell().AlignRight().Text($"{tax7Netto:N2} €"); table.Cell().AlignRight().Text($"{tax7Tax:N2} €"); } // 19% var tax19Items = Model.Items?.Where(x => x.TaxType == TaxType.Tax19).ToList() ?? []; if (tax19Items.Count > 0) { var tax19Netto = tax19Items.Sum(x => x.PriceNetto * x.Quantity); var tax19Tax = tax19Netto * 0.19; table.Cell().ColumnSpan(2).Text("zzgl. 19% USt. auf"); table.Cell().AlignRight().Text($"{tax19Netto:N2} €"); table.Cell().AlignRight().Text($"{tax19Tax:N2} €"); } table.Cell().ColumnSpan(3).Element(CellStyle).PaddingTop(10).Text("Rechnungsbetrag").Medium(); table.Cell().Element(CellStyle).PaddingTop(10).AlignRight().Text($"{Model.Items.Sum(x=> x.PriceBrutto*x.Quantity):N2} €").Medium(); return; static IContainer CellStyle(IContainer container) => container.BorderBottom(1).BorderColor(Colors.Grey.Lighten2).PaddingVertical(5); }); } private void ComposeComments(IContainer container) { container.Background(Colors.Grey.Lighten3).Padding(10).Column(column => { column.Spacing(5); column.Item().Text(Model.Comment); }); } private void ComposeFooter(IContainer container) { container.Column(outerColumn => { outerColumn.Item().DefaultTextStyle(style => style.FontSize(10)).Row(row => { row.RelativeItem().Column(column => { column.Item().Text(txt => txt.Span(Model.Seller?.Name).Bold()); column.Item().Text(txt => txt.Span(Model.Seller?.Street)); column.Item().Text(txt => txt.Span($"{Model.Seller?.Zip} {Model.Seller?.City}")); }); row.RelativeItem().Column(column => { if(!string.IsNullOrWhiteSpace(Model.Seller?.Phone)) column.Item().Text(txt => txt.Span($"Tel.: {Model.Seller?.Phone}")); if(!string.IsNullOrWhiteSpace(Model.Seller?.Email)) column.Item().Text(txt => txt.Span($"E-Mail: {Model.Seller?.Email}")); if(!string.IsNullOrWhiteSpace(Model.Seller?.Web)) column.Item().Text(txt => txt.Span($"Web: {Model.Seller?.Web}")); }); row.RelativeItem().Column(column => { if(!string.IsNullOrWhiteSpace(Model.PaymentData?.BankName)) column.Item().Text(txt => txt.Span(Model.PaymentData?.BankName)); if(!string.IsNullOrWhiteSpace(Model.PaymentData?.Iban)) column.Item().Text(txt => txt.Span($"IBAN: {Model.PaymentData?.Iban}")); if(!string.IsNullOrWhiteSpace(Model.PaymentData?.Bic)) column.Item().Text(txt => txt.Span($"BIC: {Model.PaymentData?.Bic}")); }); }); outerColumn.Item().PaddingTop(3, Unit.Millimetre).AlignCenter().Text(txt => { txt.CurrentPageNumber(); txt.Span(" / "); txt.TotalPages(); }); }); } private void ComposeHeader(IContainer container) { container.Column(outerColumn => { outerColumn.Item().AlignCenter().Row(row => { row.RelativeItem().AlignCenter().Column(col => { col.Item().Height(25, Unit.Millimetre).Image("bit.bmp"); }); }); outerColumn.Item().PaddingTop(15, Unit.Millimetre).Row(row => { row.AutoItem().Column(column => { column.Item().Text(Model.Seller?.ToString()).Style(new TextStyle().FontSize(8).SemiBold().Underline()); if(!string.IsNullOrWhiteSpace(Model.Customer?.Name)) column.Item().Text(Model.Customer?.Name); if(!string.IsNullOrWhiteSpace(Model.Customer?.Name2)) column.Item().Text(Model.Customer?.Name2); column.Item().Text(Model.Customer?.Street); column.Item().Text($"{Model.Customer?.Zip} {Model.Customer?.City}"); }); row.RelativeItem(); row.AutoItem().DefaultTextStyle(style => style.FontSize(10)).Column(column => { column.Item().Text(txt => { txt.Span("Steuer-Nr:").Bold().Underline(); txt.Span(" "); txt.Span(Model.Seller?.TaxId); }); column.Item().Text(txt => { txt.Span("Datum:").Bold().Underline(); txt.Span(" "); txt.Span(Model.IssueDate.ToShortDateString()); }); column.Item().Text(txt => { txt.Span("Rechnung:").Bold(); txt.Span(" "); txt.Span($"#{Model.InvoiceId}"); }); }); }); }); } } }