Documents: Replace Razor templates with iText
All checks were successful
Test / Run tests (push) Successful in 2m24s

This commit is contained in:
2026-03-16 15:09:47 +01:00
parent d8c967b2f2
commit 8054a024f4
61 changed files with 2291 additions and 2924 deletions

View File

@@ -1,6 +1,10 @@
using Elwig.Helpers;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using iText.Kernel.Pdf;
using iText.Layout.Borders;
using iText.Layout.Element;
using iText.Layout.Properties;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -17,7 +21,7 @@ namespace Elwig.Documents {
public string CurrencySymbol;
public int Precision;
public string MemberModifier;
public IEnumerable<(string Name, int Kg, decimal Amount)>? MemberUnderDeliveries;
public List<(string Name, int Kg, decimal Amount)>? MemberUnderDeliveries;
public decimal MemberTotalUnderDelivery;
public int MemberAutoBusinessShares;
public decimal MemberAutoBusinessSharesAmount;
@@ -53,12 +57,6 @@ namespace Elwig.Documents {
} else {
MemberModifier = "Sonstige Zu-/Abschläge";
}
Aside = Aside.Replace("</table>", "") +
$"<thead><tr><th colspan='2'>Gutschrift</th></tr></thead><tbody>" +
$"<tr><th>TG-Nr.:</th><td>{(p.Credit != null ? $"{p.Credit.Year}/{p.Credit.TgNr:000}" : "-")}</td></tr>" +
$"<tr><th>Datum:</th><td>{p.Variant.Date:dd.MM.yyyy}</td></tr>" +
$"<tr><th>Überw. am:</th><td>{p.Variant.TransferDate:dd.MM.yyyy}</td></tr>" +
$"</tbody></table>";
Text = App.Client.TextCreditNote;
DocumentId = $"Tr.-Gutschr. " + (p.Credit != null ? $"{p.Credit.Year}/{p.Credit.TgNr:000}" : p.MgNr);
CurrencySymbol = season.Currency.Symbol ?? season.Currency.Code;
@@ -96,4 +94,222 @@ namespace Elwig.Documents {
.ToList();
}
}
}}
protected override void RenderHeader(iText.Layout.Document doc, PdfDocument pdf) {
base.RenderHeader(doc, pdf);
Aside?.AddCell(NewAsideCell("Gutschrift", 2))
.AddCell(NewAsideCell("TG-Nr.:", isName: true)).AddCell(NewAsideCell(Payment?.Credit != null ? $"{Payment.Credit.Year}/{Payment.Credit.TgNr:000}" : "-"))
.AddCell(NewAsideCell("Datum:", isName: true)).AddCell(NewAsideCell($"{Payment?.Variant.Date:dd.MM.yyyy}"))
.AddCell(NewAsideCell("Überw. am:", isName: true)).AddCell(NewAsideCell($"{Payment?.Variant.TransferDate:dd.MM.yyyy}"));
}
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
base.RenderBody(doc, pdf);
doc.Add(NewCreditTable(Data));
var div = new Table(ColsMM(60, 105))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE);
var hint = new KernedParagraph(8)
.Add(Italic("Hinweis:\n" +
$"Die Summe der Lieferungen und die Summe der anfal\u00adlenden Pönalen werden mit " +
$"{Payment?.Variant.Season.Precision} Nach\u00adkomma-stellen berechnent, " +
$"erst das Ergebnis wird kauf-männisch auf 2 Nach\u00adkomma\u00adstellen gerundet."))
.SetWidth(56 * PtInMM).SetMarginsMM(4, 2, 4, 2);
div.AddCell(new Cell(1, 2).SetPadding(0).SetBorder(Border.NO_BORDER).SetBorderTop(new SolidBorder(BorderThickness)));
div.AddCell(new Cell(3, 1).SetPadding(0).SetBorder(Border.NO_BORDER).Add(hint).SetKeepTogether(true));
var tbl1 = new Table(ColsMM(70, 5, 5, 25))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetKeepTogether(true);
var tbl2 = new Table(ColsMM(70, 5, 5, 25))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetKeepTogether(true);
var tbl3 = new Table(ColsMM(70, 5, 5, 25))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetKeepTogether(true);
var sum = Data.Rows.Sum(p => p.Amount);
if (Payment == null) {
tbl1.AddCells(FormatRow("Gesamt", sum, bold: true, noTopBorder: true));
} else {
var noBorder = true;
if (Payment.NetAmount != Payment.Amount) {
tbl1.AddCells(FormatRow("Zwischensumme", Payment.NetAmount, noTopBorder: noBorder));
noBorder = false;
tbl1.AddCells(FormatRow(MemberModifier, Payment.Amount - Payment.NetAmount, add: true));
}
if (Credit == null) {
tbl1.AddCells(FormatRow("Gesamtbetrag", Payment.Amount, bold: true, noTopBorder: noBorder));
// TODO Mock VAT
} else {
var hasPrev = Credit.PrevNetAmount != null;
tbl1.AddCells(FormatRow(hasPrev ? "Gesamtbetrag" : "Nettobetrag", Credit.NetAmount, bold: true, noTopBorder: noBorder));
if (hasPrev) {
tbl1.AddCells(FormatRow("Bisher berücksichtigt", -Credit.PrevNetAmount, add: true));
tbl1.AddCells(FormatRow("Nettobetrag", Credit.NetAmount - (Credit.PrevNetAmount ?? 0)));
}
tbl1.AddCells(FormatRow($"Mehrwertsteuer ({Credit.Vat * 100} %)", Credit.VatAmount, add: true));
tbl1.AddCells(FormatRow("Bruttobetrag", Credit.GrossAmount, bold: true));
}
}
decimal penalty = 0;
string? comment = null;
if (MemberUnderDeliveries != null && MemberUnderDeliveries.Count > 0) {
tbl2.AddCell(NewTd("Anfallende Pönalen durch Unterlieferungen:", colspan: 2).SetPaddingTopMM(5))
.AddCell(NewCell(colspan: 2));
foreach (var u in MemberUnderDeliveries) {
tbl2.AddCells(FormatRow($"{u.Name} ({u.Kg:N0} kg)", u.Amount, add: true, subCat: true));
penalty += u.Amount;
}
penalty = Math.Round(penalty, 2, MidpointRounding.AwayFromZero);
}
if (MemberTotalUnderDelivery != 0) {
tbl2.AddCells(FormatRow("Unterlieferung (GA)", MemberTotalUnderDelivery, add: true));
penalty += MemberTotalUnderDelivery;
}
if (MemberAutoBusinessSharesAmount != 0) {
tbl2.AddCells(FormatRow($"Autom. Nachz. von GA ({MemberAutoBusinessShares})", MemberAutoBusinessSharesAmount, add: true));
penalty += MemberAutoBusinessSharesAmount;
}
if (CustomPayment?.Amount != null) {
comment = CustomPayment.Comment;
string text = (CustomPayment.Amount.Value < 0 ? "Weitere Abzüge" : "Weitere Zuschläge") + (comment != null ? "*" : "");
if (comment != null && comment!.Length <= 30) {
text = comment;
comment = null;
}
tbl2.AddCells(FormatRow(text, CustomPayment.Amount.Value, add: true));
penalty += CustomPayment.Amount.Value;
}
if (Credit == null) {
tbl3.AddCells(FormatRow("Auszahlungsbetrag", (Payment?.Amount + penalty) ?? (sum + penalty), bold: true));
} else {
var diff = Credit.Modifiers - penalty;
if (diff != 0) {
tbl3.AddCells(FormatRow(diff < 0 ? "Sonstige Abzüge" : "Sonstige Zuschläge", diff, add: true));
}
if (Credit.PrevModifiers != null && Credit.PrevModifiers != 0) {
tbl3.AddCells(FormatRow("Bereits berücksichtigte Abzüge", -Credit.PrevModifiers, add: true));
}
tbl3.AddCells(FormatRow("Auszahlungsbetrag", Credit.Amount, bold: true));
}
div.AddCell(new Cell().SetPadding(0).SetBorder(Border.NO_BORDER).Add(tbl1));
div.AddCell(new Cell().SetPadding(0).SetBorder(Border.NO_BORDER).Add(tbl2));
div.AddCell(new Cell().SetPadding(0).SetBorder(Border.NO_BORDER).Add(tbl3));
doc.Add(div);
if (comment != null) {
doc.Add(new KernedParagraph($"*{comment}", 12).SetMarginTopMM(10));
}
doc.Add(new KernedParagraph($"Überweisung erfolgt auf Konto {Utils.FormatIban(Member.Iban ?? "-")}.", 12).SetPaddingTopMM(10));
if (Text != null) {
doc.Add(new KernedParagraph(Text, 12).SetMarginTop(12).SetKeepTogether(true));
}
}
protected Cell[] FormatRow(string name, decimal? value, bool add = false, bool bold = false, bool subCat = false, bool noTopBorder = false) {
float textSize = subCat ? 8 : !add ? 12 : 10;
float numSize = subCat ? 8 : 12;
var border = !add && !noTopBorder;
var pad = !add && !noTopBorder ? 1 : 0.5f;
return [
NewTd($"{name}:", textSize, bold: bold, borderTop: border).SetPaddingTopMM(pad),
NewTd(value < 0 ? "" : (add ? "+" : ""), numSize, right: true, bold: bold, borderTop: border).SetPaddingTopMM(pad),
NewTd(CurrencySymbol, numSize, bold: bold, borderTop: border).SetPaddingTopMM(pad),
NewTd($"{Math.Abs(value ?? 0):N2}", numSize, right: true, bold: bold, borderTop: border).SetPaddingTopMM(pad),
];
}
protected Table NewCreditTable(CreditNoteDeliveryData data) {
var tbl = new Table(ColsMM(25, 6, 36, 10, 10, 15, 12, 13, 5, 17, 16), true)
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE);
tbl.AddHeaderCell(NewTh("Lieferschein-Nr.", rowspan: 2, left: true))
.AddHeaderCell(NewTh("Pos.", rowspan: 2).SetPaddingLeft(0).SetPaddingRight(0))
.AddHeaderCell(NewTh("Sorte/Attribut/Bewirtschaftg.\nZu-/Abschlag", rowspan: 2, left: true))
.AddHeaderCell(NewTh("Gradation", colspan: 2))
.AddHeaderCell(NewTh("Flächenbindung", colspan: 2))
.AddHeaderCell(NewTh("Preis"))
.AddHeaderCell(NewTh("Rbl.").SetPaddingLeft(0).SetPaddingRight(0))
.AddHeaderCell(NewTh("Zu-/Abschläge").SetPaddingLeft(0).SetPaddingRight(0))
.AddHeaderCell(NewTh("Betrag"))
.AddHeaderCell(NewTh("[°Oe]"))
.AddHeaderCell(NewTh("[°KMW]").SetPaddingLeft(0).SetPaddingRight(0))
.AddHeaderCell(NewTh("[kg]", colspan: 2))
.AddHeaderCell(NewTh($"[{CurrencySymbol}/kg]"))
.AddHeaderCell(NewTh("[%]").SetPaddingLeft(0).SetPaddingRight(0))
.AddHeaderCell(NewTh($"[{CurrencySymbol}]"))
.AddHeaderCell(NewTh($"[{CurrencySymbol}]"));
foreach (var p in data.Rows) {
var sub = new Table(ColsMM(25, 6, 36, 10, 10, 15, 12, 13, 5, 17, 16))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetKeepTogether(true);
var attr = p.Attribute != null || p.Cultivation != null || p.QualId == "WEI";
var rows = Math.Max(p.Buckets.Length, 1 + (attr ? 1 : 0) + p.Modifiers.Length);
for (int i = 0; i < rows; i++) {
if (i == 0) {
sub.AddCell(NewTd(p.LsNr))
.AddCell(NewTd($"{p.DPNr:N0}", center: true).SetPaddingLeft(0).SetPaddingRight(0))
.AddCell(NewTd(p.Variety))
.AddCell(NewTd($"{p.Gradation.Oe:N0}", center: true))
.AddCell(NewTd($"{p.Gradation.Kmw:N1}", center: true));
} else if (i == 1 && attr) {
var varibute = new KernedParagraph(8);
if (p.Attribute != null) varibute.Add(Normal(p.Attribute));
if (p.Attribute != null && p.Cultivation != null) varibute.Add(Normal(" / "));
if (p.Cultivation != null) varibute.Add(Normal(p.Cultivation));
if ((p.Attribute != null || p.Cultivation != null) && p.QualId == "WEI") varibute.Add(Normal(" / "));
if (p.QualId == "WEI") varibute.Add(Italic("abgew."));
sub.AddCell(NewCell(colspan: 2))
.AddCell(NewTd(varibute, colspan: 3).SetPaddingTop(0));
} else if (i - (rows - p.Modifiers.Length) < p.Modifiers.Length) {
sub.AddCell(NewCell(colspan: 2))
.AddCell(NewTd(p.Modifiers[i - (rows - p.Modifiers.Length)], 8, colspan: 3).SetPaddingTop(0).SetPaddingLeftMM(5));
} else {
sub.AddCell(NewCell(colspan: 5));
}
if (i < p.Buckets.Length) {
var bucket = p.Buckets[i];
var pad = i == 0 ? 0.5f : 0;
sub.AddCell(NewTd($"{bucket.Name}:", 8)
.SetPaddingTopMM(pad))
.AddCell(NewTd($"{bucket.Value:N0}", right: true)
.SetPaddingTopMM(pad))
.AddCell(NewTd($"{bucket.Price:N4}", right: true)
.SetPaddingTopMM(pad));
} else {
sub.AddCell(NewCell(colspan: 3));
}
if (i == p.Buckets.Length - 1) {
var rebelMod = p.WeighingModifier * 100;
var totalMod = p.TotalModifiers ?? 0;
var pad = i == 0 ? 0.5f : 0;
sub.AddCell(NewTd(rebelMod == 0 ? "-" : (Utils.GetSign(rebelMod) + $"{Math.Abs(rebelMod):0.0##}"), 6, center: true)
.SetPaddingTopMM(pad))
.AddCell(NewTd(totalMod == 0 ? "-" : Utils.GetSign(totalMod) + $"{Math.Abs(totalMod):N2}", center: totalMod == 0, right: true)
.SetPaddingTopMM(pad))
.AddCell(NewTd($"{p.Amount:N2}", right: true)
.SetPaddingTopMM(pad));
} else {
sub.AddCell(NewCell(colspan: 3));
}
}
tbl.AddCell(new Cell(1, 12).SetPadding(0).SetBorder(Border.NO_BORDER).Add(sub));
}
return tbl;
}
}
}