diff --git a/History.md b/History.md index 24a6cde6..ec53ee21 100644 --- a/History.md +++ b/History.md @@ -155,7 +155,7 @@ corrections - #707 invoiceimporter may fail if certain values are not set - #708 embedded files cannot be determined - #709 ZUGFeRDInvoiceImporter ignored "first" embedded file in list of pdf attachments -- #607 Enable flexible PaymentReference and a DocumentName. +- #607 Enable flexible PaymentReference and a DocumentName. **Important note:** The library’s behavior for generating ZUGFeRD 2 documents is not fully backward compatible. Except for the “Minimum” profile, BT‑83 was automatically populated with the document number in earlier versions. From this release onward, applications must explicitly set BT‑83. - #649 Reuse toPDF method to work without any dependencies to the file system - #650 Add net.sf.offo:fop-hyph - #665 Fix #632: Return ubl_creditnote as Standard for CreditNotes diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java index eff70131..b385ee84 100644 --- a/library/src/main/java/org/mustangproject/Item.java +++ b/library/src/main/java/org/mustangproject/Item.java @@ -43,6 +43,8 @@ public class Item implements IZUGFeRDExportableItem { protected ArrayList Charges = new ArrayList<>(); protected List includedNotes = null; protected String accountingReference; + protected String parentLineID = null; + protected String lineStatusReasonCode = null; //protected HashMap attributes = new HashMap<>(); /*** @@ -91,9 +93,11 @@ public class Item implements IZUGFeRDExportableItem { }); - itemMap.getAsNodeMap("AssociatedDocumentLineDocument") - .flatMap(icnm -> icnm.getAsString("LineID")) - .ifPresent(this::setId); + itemMap.getAsNodeMap("AssociatedDocumentLineDocument").ifPresent(adld -> { + adld.getAsString("LineID").ifPresent(this::setId); + adld.getAsString("ParentLineID").ifPresent(this::setParentLineID); + adld.getAsString("LineStatusReasonCode").ifPresent(this::setLineStatusReasonCode); + }); itemMap.getAsNodeMap("Price").ifPresent(icnm -> { // ubl @@ -189,6 +193,9 @@ public class Item implements IZUGFeRDExportableItem { icnm.getAsNodeMap("ApplicableTradeTax") .flatMap(cnm -> cnm.getAsString("ExemptionReason")) .ifPresent(product::setTaxExemptionReason); + icnm.getAsNodeMap("ApplicableTradeTax") + .flatMap(cnm -> cnm.getAsString("ExemptionReasonCode")) + .ifPresent(product::setTaxExemptionReasonCode); icnm.getAllNodes("SpecifiedTradeAllowanceCharge").map(NodeMap::new).forEach(stac -> { stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> { @@ -644,4 +651,34 @@ public class Item implements IZUGFeRDExportableItem { public String getAccountingReference() { return accountingReference; } + + @Override + public String getParentLineID() { + return parentLineID; + } + + /*** + * for sub invoice lines: set the parent line ID + * @param parentLineID the line ID of the parent line + * @return fluent setter + */ + public Item setParentLineID(String parentLineID) { + this.parentLineID = parentLineID; + return this; + } + + @Override + public String getLineStatusReasonCode() { + return lineStatusReasonCode; + } + + /*** + * for sub invoice lines: set the status reason code (DETAIL, GROUP, INFORMATION) + * @param lineStatusReasonCode the status reason code + * @return fluent setter + */ + public Item setLineStatusReasonCode(String lineStatusReasonCode) { + this.lineStatusReasonCode = lineStatusReasonCode; + return this; + } } diff --git a/library/src/main/java/org/mustangproject/Product.java b/library/src/main/java/org/mustangproject/Product.java index a472ac4a..be0d19cb 100644 --- a/library/src/main/java/org/mustangproject/Product.java +++ b/library/src/main/java/org/mustangproject/Product.java @@ -23,6 +23,7 @@ public class Product implements IZUGFeRDExportableProduct { protected String unit, name, sellerAssignedID, buyerAssignedID; protected String description = ""; protected String taxExemptionReason = null; + protected String taxExemptionReasonCode = null; protected String taxCategoryCode = null; protected BigDecimal VATPercent; protected boolean isReverseCharge = false; @@ -157,7 +158,22 @@ public class Product implements IZUGFeRDExportableProduct { * @return fluent setter */ public Product setTaxExemptionReason(String taxExemptionReasonText) { - taxExemptionReason = taxExemptionReasonText; + this.taxExemptionReason = taxExemptionReasonText; + return this; + } + + @Override + public String getTaxExemptionReasonCode() { + return taxExemptionReasonCode; + } + + /*** + * + * @param taxExemptionReasonCode, https://docs.peppol.eu/poacc/billing/3.0/codelist/vatex/ + * @return fluent setter + */ + public Product setTaxExemptionReasonCode(String taxExemptionReasonCode) { + this.taxExemptionReasonCode = taxExemptionReasonCode; return this; } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java index 05f4d437..7b48ab5f 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java @@ -192,6 +192,36 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{ return null; } + /*** + * for sub invoice lines in ZUGFeRD Extended: the line ID of the parent line + * @return the parent line ID or null if this is a top-level line + */ + default String getParentLineID() { + return null; + } + + /*** + * for sub invoice lines in ZUGFeRD Extended: the status reason code + * determines if a line is relevant for calculation + * @return DETAIL, GROUP, INFORMATION or null for standard lines + */ + default String getLineStatusReasonCode() { + return null; + } + + /*** + * checks if this line should be included in sum calculation. + * GROUP and INFORMATION lines are not calculation-relevant, + * only DETAIL lines (or lines without status code) are. + * @return true if the line should be included in calculation + */ + @com.fasterxml.jackson.annotation.JsonIgnore + default boolean isCalculationRelevant() { + String status = getLineStatusReasonCode(); + // null means standard line (backwards compatible), DETAIL is explicitly relevant + return status == null || "DETAIL".equals(status); + } + /** * A grouping of business terms to indicate accounting-relevant free texts including a qualification of these. * diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java index 71402d8b..2ce6909c 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java @@ -158,6 +158,10 @@ public interface IZUGFeRDExportableProduct { return null; } + default String getTaxExemptionReasonCode() { + return null; + } + default String getCountryOfOrigin() { return null; } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java b/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java index 3778a7cc..8b823e5f 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java @@ -155,12 +155,15 @@ public class TransactionCalculator implements IAbsoluteValueProvider { /*** * returns the total net value of all items, without document level - * charges/allowances + * charges/allowances. For sub invoice lines only DETAIL lines are summed, + * GROUP and INFORMATION lines are ignored. * * @return item sum */ protected BigDecimal getTotal() { - BigDecimal dec = Stream.of(trans.getZFItems()).map(LineCalculator::new) + BigDecimal dec = Stream.of(trans.getZFItems()) + .filter(IZUGFeRDExportableItem::isCalculationRelevant) + .map(LineCalculator::new) .map(LineCalculator::getItemTotalNetAmount).reduce(ZERO, BigDecimal::add); return dec; } @@ -189,6 +192,10 @@ public class TransactionCalculator implements IAbsoluteValueProvider { final String vatDueDateTypeCode = trans.getVATDueDateTypeCode(); for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { + // skip GROUP and INFORMATION lines for sub invoice lines + if (!currentItem.isCalculationRelevant()) { + continue; + } BigDecimal percent = null; if (currentItem.getProduct() != null) { percent = currentItem.getProduct().getVATPercent(); @@ -254,7 +261,12 @@ public class TransactionCalculator implements IAbsoluteValueProvider { protected List getVATAmountList() { final List vatAmounts = new ArrayList<>(); final String vatDueDateTypeCode = this.trans.getVATDueDateTypeCode(); - for (final IZUGFeRDExportableItem currentItem : this.trans.getZFItems()) { + for (final IZUGFeRDExportableItem currentItem : this.trans.getZFItems()) + { + // skip GROUP and INFORMATION lines for sub invoice lines + if (!currentItem.isCalculationRelevant()) { + continue; + } BigDecimal percent = null; if (currentItem.getProduct() != null) { percent = currentItem.getProduct().getVATPercent(); diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index ded4e1b6..4fc4aeec 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -537,6 +537,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { if (currentItem.getProduct().getTaxExemptionReason() != null) { xml += "" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + ""; } + if (currentItem.getProduct().getTaxExemptionReasonCode() != null) { + xml += "" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReasonCode()) + ""; + } xml += "" + currentItem.getProduct().getTaxCategoryCode() + ""; BigDecimal vatValue=BigDecimal.ZERO; if (currentItem.getProduct().getTaxCategoryCode().equals(TaxCategoryCodeTypeConstants.ZEROTAXPRODUCTS)) { @@ -1009,11 +1012,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { ArrayList paymentTerms = new ArrayList(Arrays.asList(trans.getExtendedPaymentTerms())); - IZUGFeRDPaymentTerms izpt= trans.getPaymentTerms(); - if (izpt!=null) { - paymentTerms.add(izpt); - } - String paymentTermsXml = ""; if (paymentTerms.size() == 0) { return ""; diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java index d81dd29d..15c7d07a 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java @@ -160,7 +160,7 @@ public class ZF2PushTest extends TestCase { .setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711") .setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE"))) .setNumber(number) - .addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(0)).setTaxExemptionReason("Kleinunternehmer gemäß §19 UStG").setTaxCategoryCode("E"), price, new BigDecimal(1.0)).addNote(theNote)) + .addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(0)).setTaxExemptionReason("Kleinunternehmer gemäß §19 UStG").setTaxCategoryCode("E").setTaxExemptionReasonCode( "VATEX-EU-I" ), price, new BigDecimal(1.0)).addNote(theNote)) ); String theXML = new String(ze.getProvider().getXML(), StandardCharsets.UTF_8); assertTrue(theXML.contains(" 1.3 (GROUP) -> 1.3.1 (DETAIL) + Item group1 = findItemById(invoice, "1"); + assertNotNull(group1); + assertEquals("GROUP", group1.getLineStatusReasonCode()); + + Item group13 = findItemById(invoice, "1.3"); + assertNotNull(group13); + assertEquals("GROUP", group13.getLineStatusReasonCode()); + assertEquals("1", group13.getParentLineID()); + + Item detail131 = findItemById(invoice, "1.3.1"); + assertNotNull(detail131); + assertEquals("DETAIL", detail131.getLineStatusReasonCode()); + assertEquals("1.3", detail131.getParentLineID()); + + // verify calculation only includes DETAIL lines + // DETAIL: 1.1=30, 1.2=60, 1.3.1=90, 1.3.2=36 = 216 + TransactionCalculator tc = new TransactionCalculator(invoice); + assertEquals(new BigDecimal("216.00"), tc.getTotal().setScale(2)); + } + + @Test + public void testSubInvoiceLinesWithDiscounts() throws FileNotFoundException, XPathExpressionException, ParseException { + // test sub invoice lines with negative amounts (discounts) + File inputFile = getResourceAsFile("subinvoicelines/Extended___SubInvoiceLines_Buero_Material_Bsp3__.xml"); + ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(); + zii.setInputStream(new FileInputStream(inputFile)); + + Invoice invoice = zii.extractInvoice(); + + // verify calculation handles negative DETAIL lines correctly + // GROUP 01: 600 + 450 - 50 = 1000 + // GROUP 02: 360 + 90 - 45 = 405 + // Total DETAIL: 1405 + TransactionCalculator tc = new TransactionCalculator(invoice); + assertEquals(new BigDecimal("1405.00"), tc.getTotal().setScale(2)); + } + + @Test + public void testSubInvoiceLinesInformation() throws FileNotFoundException, XPathExpressionException, ParseException { + // test INFORMATION lines (should have price 0 and not affect calculation) + File inputFile = getResourceAsFile("subinvoicelines/Extended_Fallschutz-Set_SubInvoiceLine_Bsp5.xml"); + ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(); + zii.setInputStream(new FileInputStream(inputFile)); + + Invoice invoice = zii.extractInvoice(); + + // find INFORMATION lines + Item info0101 = findItemById(invoice, "01.01"); + assertNotNull(info0101); + assertEquals("INFORMATION", info0101.getLineStatusReasonCode()); + assertFalse(info0101.isCalculationRelevant()); + + // DETAIL line 01 = 45000 + TransactionCalculator tc = new TransactionCalculator(invoice); + assertEquals(new BigDecimal("45000.00"), tc.getTotal().setScale(2)); + } + + private Item findItemById(Invoice invoice, String id) { + for (IZUGFeRDExportableItem item : invoice.getZFItems()) { + if (item instanceof Item && id.equals(((Item) item).getId())) { + return (Item) item; + } + } + return null; + } } diff --git a/library/src/test/resources/subinvoicelines/Extended_Fallschutz-Set_SubInvoiceLine_Bsp5.xml b/library/src/test/resources/subinvoicelines/Extended_Fallschutz-Set_SubInvoiceLine_Bsp5.xml new file mode 100644 index 00000000..9f799e1c --- /dev/null +++ b/library/src/test/resources/subinvoicelines/Extended_Fallschutz-Set_SubInvoiceLine_Bsp5.xml @@ -0,0 +1,408 @@ + + + + + + + + urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended + + + + 9099999999 + RECHNUNG + 380 + + 20261031 + + + Geschäftsführer: Herr Geschäftsführer , Muster Maschinenbau GmbH etc. + REG + + + Es bestehen Vereinbarungen, aus denen sich Minderungen des Entgelts ergeben können. + AAI + + + ZUGFeRD vers 2.4.0 (Extended) + ACB + + + Dies ist eine Beispiel-Rechnung zur empfohlenen Darstellung von Unterpositionen für ein Verkaufsset + ACB + + + + + + 01 + DETAIL + + + 99999999999 + 99999000000090 1 + INDIVIDUELLES Fallschutzset + Kundenindividuelles Sortiment Fallschutz + + + + 4500.00 + 1.0000 + + + 4500.00 + 1.0000 + + + + 10.00 + + 0009999999 + Muster Bau und Fassaden GmbH + + 76543 + Muster Str. 19 + Musterhausen + DE + + + + + + VAT + S + 19.00 + + + + 20261006 + + + 20261021 + + + + 45000.00 + 0.00 + + + 2133367983 + 130 + VN + + + + + + 01.01 + 01 + INFORMATION + + + 9947376819504 + 1239932943961 1 + RUCKSACK-Fallschutz + + + + 0.00 + + + + 10.00 + + + + VAT + S + 19.00 + + + 0.00 + + + + + + 01.02 + 01 + INFORMATION + + + 9961975355683 + 1234300430961 1 + Gehörschutz + + + + 0.00 + + + + 10.00 + + + + VAT + S + 19.00 + + + 0.00 + + + + + + 01.03 + 01 + INFORMATION + + + 9945727365021 + 1234102250061 1 + Schutzbrille-KLAR + + + + 0.00 + + + + 10.00 + + + + VAT + S + 19.00 + + + 0.00 + + + + + + 01.04 + 01 + INFORMATION + + + 9953479245027 + 1234200243961 1 + Schutzhelm-6PUNKT-WEISS + + + + 0.00 + + + + 10.00 + + + + VAT + S + 19.00 + + + 0.00 + + + + + + GLN4000000000 + Lieferant GmbH & Co. KG + + Georg Verkäufer + + 0160 123456789 + + + georg.Verkäufer@lieferant.de + + + + 98765 + Lieferanten-Str.12-17 + Lieferstadt + DE + + + info@lieferant.de + + + 78910/12345 + + + DE12435679 + + + + 21212121 + Muster Maschinenbau GmbH + + 87654 + Käufer-Str. 12 + Käuferstadt + DE + + + + 555555555 + + 20261031 + + + + 456789123 + + + + + 0009999999 + Muster Bau und Fassaden GmbH + + 76543 + Muster Str. 19 + Musterhausen + DE + + + + + 20261031 + + + + 8876543219 + + 20261031 + + + + + Kundennummer:. 8888855555 Rechnungsnummer:. 6069999999 + EUR + + 58 + Bezahlung per SEPA Überweisung + + DE75512108001245126199 + + + SOLADESTXYZ + + + + 8550.00 + VAT + 45000.00 + S + 19.00 + + + Bis zum 29.11.2026 ohne Abzug + + 20261129 + + + + 45000.00 + 0.00 + 45000.00 + 8550.00 + 53550.00 + 53550.00 + + + + diff --git a/library/src/test/resources/subinvoicelines/Extended_SubInvoiceLines_Hardware_Bsp2.xml b/library/src/test/resources/subinvoicelines/Extended_SubInvoiceLines_Hardware_Bsp2.xml new file mode 100644 index 00000000..a3c1a947 --- /dev/null +++ b/library/src/test/resources/subinvoicelines/Extended_SubInvoiceLines_Hardware_Bsp2.xml @@ -0,0 +1,443 @@ + + + + + + + + urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended + + + + 99877 + 380 + + 20260530 + + + Geschäftsführer: Herr Geschäftsführer , Muster Bau GmbH etc. + REG + + + Es bestehen Vereinbarungen, aus denen sich Minderungen des Entgelts ergeben können. + AAI + + + ZUGFeRD vers 2.4.0 Extended + ACB + + + Dies ist eine Beispiel-Rechnung zur empfohlenen Darstellung von Unterpositionen + ACB + + + + + + 0101 + 01 + DETAIL + + + 88888886349852 + 123456789 + 987654321 + Laser printer B/W + Schwarzweiß Laserdrucker + + + + 300.00 + + + + 2.00 + + + + VAT + S + 19.00 + + + 600.00 + + + + + + 0102 + 01 + DETAIL + + + 77777776349852 + 2345678910 + 876543219 + Ink printer color + Farbdrucker + + + + 150.00 + + + + 3.00 + + + + VAT + S + 19.00 + + + 450.00 + + + + + + 01 + GROUP + + + 6666656349852 + 345678912 + 765432198 + Subtotal hardware + Hardware Gesamt + + + + 1050.00 + + + + 1.00 + + + + VAT + S + 19.00 + + + 1050.00 + + + + + + 0201 + 02 + DETAIL + + + 55555556349852 + 456789123 + 654321987 + Toner + Toner + + + + 120.00 + + + + 3.00 + + + + VAT + S + 19.00 + + + 360.00 + + + + + + 0202 + 02 + DETAIL + + + 5555556349852 + 567891234 + 543219876 + PAPER + Kopierpapier + + + + 9.00 + + + + 10.00 + + + + VAT + S + 19.00 + + + 90.00 + + + + + + 02 + GROUP + + + 2222256349852 + 9345678912 + 9765432198 + Subtotal Accessories + Zubehör Gesamt + + + + 450.00 + + + + 1.00 + + + + VAT + S + 19.00 + + + 450.00 + + + + + Kundenref. BT-10 + + 998877 + Musterbetrieb Systemhaus AG + + HRA 45678 + + + Kontaktperson + + 5578 + + + absender@musterberieb.de + + + + 37079 + August-Müller-Strasse 222 + Göttingen + DE + + + DE09687654321 + + + + 330145 + Auftraggeber Firmenkunde GmbH + + Herr Thomas Auftraggeber + + +49 321 456789 + + + thomas.auftraggeber@Firmenkunde.de + + + + 37073 + Musterstraße 1212 + Göttingen + DE + + + DE1234567890 + + + + G12042-1-01 + + + BT-13 + + + Vertragsnr. BT-12 + + + Vergabenr. BT-17 + 50 + + + Projektnr. BT-11 + Project reference + + + + + Auftraggeber Firmenkunde GmbH + + 37073 + Musterstraße 1212 + Göttingen + DE + + + + + 20260530 + + + + + EUR + + 58 + + DE75512108001245126199 + Musterbetrieb Kontoname + + + PBNKDEFF + + + + 285.00 + VAT + 1500.00 + S + 19.00 + + + Bei Zahlung bis zum 06.06.2026 zahlen Sie mit 2,00 % Skonto € 1749,30 € + + 20260606 + + + 1785.00 + 2.00 + + + + Bis zum zum 13.06.2026 ohne Abzug + + 20260613 + + + + 1500.00 + 0.00 + 0.00 + 1500.00 + 285.00 + 1785.00 + 0.00 + 1785.00 + + + Kostenstelle BT-19 + + + + diff --git a/library/src/test/resources/subinvoicelines/Extended___SubInvoiceLines_Buero_Material_Bsp3__.xml b/library/src/test/resources/subinvoicelines/Extended___SubInvoiceLines_Buero_Material_Bsp3__.xml new file mode 100644 index 00000000..0556e885 --- /dev/null +++ b/library/src/test/resources/subinvoicelines/Extended___SubInvoiceLines_Buero_Material_Bsp3__.xml @@ -0,0 +1,507 @@ + + + + + + + + urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended + + + + 99877 + 380 + + 20260530 + + + Geschäftsführer: Herr Geschäftsführer , Muster Bau GmbH etc. + REG + + + Es bestehen Vereinbarungen, aus denen sich Minderungen des Entgelts ergeben können. + AAI + + + ZUGFeRD vers 2.4.0 Extended + ACB + + + Dies ist eine Beispiel-Rechnung zur empfohlenen Darstellung von Unterpositionen + ACB + + + + + + 0101 + 01 + DETAIL + + + 88888886349852 + 123456789 + 987654321 + Laser printer B/W + Schwarzweiß Laserdrucker + + + + 300.00 + + + + 2.00 + + + + VAT + S + 19.00 + + + 600.00 + + + + + + 0102 + 01 + DETAIL + + + 77777776349852 + 2345678910 + 876543219 + Ink printer color + Farbdrucker + + + + 150.00 + + + + 3.00 + + + + VAT + S + 19.00 + + + 450.00 + + + + + + 0103 + 01 + DETAIL + + + 0000006349852 + 99992345678910 + 88888876543219 + Allowance + Abschlagsposition + + + + 50.00 + + + + -1.00 + + + + VAT + S + 19.00 + + + -50.00 + + + + + + 01 + GROUP + + + 6666656349852 + 345678912 + 765432198 + Subtotal hardware + Hardware Gesamt + + + + 1000.00 + + + + 1.00 + + + + VAT + S + 19.00 + + + 1000.00 + + + + + + 0201 + 02 + DETAIL + + + 55555556349852 + 456789123 + 654321987 + Toner + Toner + + + + 120.00 + + + + 3.00 + + + + VAT + S + 19.00 + + + 360.00 + + + + + + 0202 + 02 + DETAIL + + + 5555556349852 + 567891234 + 543219876 + PAPER + Kopierpapier + + + + 9.00 + + + + 10.00 + + + + VAT + S + 19.00 + + + 90.00 + + + + + + 0203 + 02 + DETAIL + + + 0000006349852 + 99992345678910 + 88888876543219 + Allowance + Abschlagsposition 10% von 450,- + + + + 45.00 + + + + -1.00 + + + + VAT + S + 19.00 + + + -45.00 + + + + + + 02 + GROUP + + + 2222256349852 + 9345678912 + 9765432198 + Subtotal Accessories + Zubehör Gesamt + + + + 405.00 + + + + 1.00 + + + + VAT + S + 19.00 + + + 405.00 + + + + + Kundenref. BT-10 + + 998877 + Musterbetrieb Systemhaus AG + + HRA 45678 + + + Kontaktperson + + 5578 + + + absender@musterberieb.de + + + + 37079 + August-Müller-Strasse 222 + Göttingen + DE + + + DE09687654321 + + + + 330145 + Auftraggeber Firmenkunde GmbH + + Herr Thomas Auftraggeber + + +49 321 456789 + + + thomas.auftraggeber@Firmenkunde.de + + + + 37073 + Musterstraße 1212 + Göttingen + DE + + + DE1234567890 + + + + G12042-1-01 + + + BT-13 + + + Vertragsnr. BT-12 + + + Vergabenr. BT-17 + 50 + + + Projektnr. BT-11 + Project reference + + + + + Auftraggeber Firmenkunde GmbH + + 37073 + Musterstraße 1212 + Göttingen + DE + + + + + 20260530 + + + + + EUR + + 58 + + DE75512108001245126199 + Musterbetrieb Kontoname + + + PBNKDEFF + + + + 266.95 + VAT + 1405.00 + S + 19.00 + + + Bei Zahlung bis zum 06.06.2026 zahlen Sie mit 2,00 % Skonto € 1638,51 € + + 20260606 + + + 1671.95 + 2.00 + + + + Bis zum zum 13.06.2026 ohne Abzug + + 20260613 + + + + 1405.00 + 0.00 + 0.00 + 1405.00 + 266.95 + 1671.95 + 0.00 + 1671.95 + + + Kostenstelle BT-19 + + + + diff --git a/library/src/test/resources/subinvoicelines/Extended___SubInvoiceLines_Kaffee_Bundle_Set_Bsp4__.xml b/library/src/test/resources/subinvoicelines/Extended___SubInvoiceLines_Kaffee_Bundle_Set_Bsp4__.xml new file mode 100644 index 00000000..1a5f86d2 --- /dev/null +++ b/library/src/test/resources/subinvoicelines/Extended___SubInvoiceLines_Kaffee_Bundle_Set_Bsp4__.xml @@ -0,0 +1,458 @@ + + + + + + + + urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended + + + + 50099877 + 380 + + 20260530 + + + Geschäftsführer: Herr Geschäftsführer , Muster GmbH etc. + REG + + + Es bestehen Vereinbarungen, aus denen sich Minderungen des Entgelts ergeben können. + AAI + + + ZUGFeRD vers 2.4.0 Extended + ACB + + + Dies ist eine Beispiel-Rechnung zur empfohlenen Darstellung von Unterpositionen im Bundle mit verschiedenen Steuersätzen + ACB + + + + + + 1 + GROUP + + Positionswert nicht Rechnungs- bzw. Steuerrelevant - Zusammenfassung der steuerrelevanten Unterpositionen + + + + 88888886349852 + 123456789 + 987654321 + Kaffee-Display "Delicous" + Kaffee-Display / Bundle/Set bestehend aus folgenden Positionen + + + + 108.00 + + + + 2.00 + 1.00 + + + + VAT + S + 0.00 + + + 216.00 + + + + + + 1.1 + 1 + DETAIL + + + 77777776349852 + 2345678910 + 876543219 + Kenia Röstung + feinste Röstung + + + + 5.00 + + + + 6.00 + + + + VAT + S + 7.00 + + + 30.00 + + + + + + 1.2 + 1 + DETAIL + + + 0000006349852 + 99992345678910 + 88888876543219 + Dunkle Röstung + feinste Röstung dunkel + + + + 5.00 + + + + 12.00 + + + + VAT + S + 7.00 + + + 60.00 + + + + + + 1.3 + 1 + GROUP + + Positionswert nicht Rechnungs- bzw. Steuerrelevant - Zusammenfassung der steuerrelevanten Unterpositionen + + + + 6666656349852 + 345678912 + 765432198 + Colombia Bundle + Bundle/Set kolumbianische Röstung + + + + 21.00 + + + + 6.00 + + + + VAT + S + 0.00 + + + 126.00 + + + + + + 1.3.1 + 1.3 + DETAIL + + + 55555556349852 + 456789123 + 654321987 + Colombia Roast + kolumbianische Röstung + + + + 5.00 + + + + 18.00 + + + + VAT + S + 7.00 + + + 90.00 + + + + + + 1.3.2 + 1.3 + DETAIL + + + 5555556349852 + 567891234 + 543219876 + Becher + Kaffeebecher Sonderanfertigung + + + + 2.00 + + + + 18.00 + + + + VAT + S + 19.00 + + + 36.00 + + + + + Kundenref. BT-10 + + 998877 + Musterbetrieb Kaffee AG + + HRA 45678 + + + Kontaktperson + + 5578 + + + absender@musterberieb.de + + + + 37079 + August-Müller-Strasse 222 + Göttingen + DE + + + DE09687654321 + + + + 330145 + Auftraggeber Kaffeehaus GmbH + + Herr Thomas Auftraggeber + + +49 321 456789 + + + thomas.auftraggeber@Firmenkunde.de + + + + 37073 + Musterstraße 1212 + Göttingen + DE + + + DE1234567890 + + + + G12042-1-01 + + + BT-13 + + + Vertragsnr. BT-12 + + + Vergabenr. BT-17 + 50 + + + Projektnr. BT-11 + Project reference + + + + + Auftraggeber Kaffeehaus GmbH + + 37073 + Musterstraße 1212 + Göttingen + DE + + + + + 20260530 + + + + + EUR + + 58 + + DE75512108001245126199 + Musterbetrieb Kontoname + + + PBNKDEFF + + + + 12.60 + VAT + 180.00 + S + 7.00 + + + 6.84 + VAT + 36.00 + S + 19.00 + + + Bei Zahlung bis zum 06.06.2026 zahlen Sie mit 2,00 % Skonto € 230,73 € + + 20260606 + + + 235.44 + 2.00 + + + + Bis zum zum 13.06.2026 ohne Abzug + + 20260613 + + + + 216.00 + 0.00 + 0.00 + 216.00 + 19.44 + 235.44 + 0.00 + 235.44 + + + Kostenstelle BT-19 + + + + diff --git a/library/src/test/resources/subinvoicelines/ZUGFeRD_Extended__Abschlagsrechnung_SubInvoiceLine_u_LV_Nr_.xml b/library/src/test/resources/subinvoicelines/ZUGFeRD_Extended__Abschlagsrechnung_SubInvoiceLine_u_LV_Nr_.xml new file mode 100644 index 00000000..244250cd --- /dev/null +++ b/library/src/test/resources/subinvoicelines/ZUGFeRD_Extended__Abschlagsrechnung_SubInvoiceLine_u_LV_Nr_.xml @@ -0,0 +1,473 @@ + + + + + + + + urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended + + + + 210111 mit LV + 875 + + 20260530 + + + 1. Abschlagsrechnung + ACB + + + Geschäftsführer: Herr Geschäftsführer , Muster Bau GmbH etc. + REG + + + Es bestehen Vereinbarungen, aus denen sich Minderungen des Entgelts ergeben können. + AAI + + + ZUGFeRD vers 2.4.0 Extended + ACB + + + Dies ist eine Beispiel-Rechnung zur Darstellung einer Bau-Abschlags-Rechnung mit Sub-Invoice-Lines und Leistungsverzeichnis-Bezug je Position + ACB + + + Betreff zum LV für eine Kurzinformation zum Bauvorhaben BT-22 + ACB + + + Kopftext für zusätzliche Beschreibungen zur Rechnung. Z.B. als Anschreiben für die Rechnung BT-22 + ACB + + + ergänzneder Fußtext für die Rechnung mit zusätzlichen Angaben. Z.B: Ist kein gesondertes Lieferdatum angegeben, entspricht das Rechnungsdatum dem Datum der Lieferung und Leistung + ACB + + + freier Text zur Rechnung BT-22 + ACB + + + + + + 01.01 + 01 + GROUP + + + Baugelände abräumen Anfallender Schutt, Pflanzenreste und Müll entsorgen + + + + 7.00 + + + + 300.00 + + + + VAT + S + 19.00 + + + 2100.00 + + + + + + 01.01.01 + 01.01 + DETAIL + + + Baugelände abräumen + + + + LV 1.1.1.1.1. + LV000001.1 + 130 + Leistungsverzeichnis + BD + + + 7.00 + + + + 100.00 + + + + VAT + S + 19.00 + + + 700.00 + + + + + + 01.01.02 + 01.01 + DETAIL + + + Anfallender Pflanzenreste entsorgen + + + + LV 1.1.1.1.1. + LV000001.2 + 130 + Leistungsverzeichnis + BD + + + 7.00 + + + + 100.00 + + + + VAT + S + 19.00 + + + 700.00 + + + + + + 01.01.03 + 01.01 + DETAIL + + + Müll entsorgen + + + + LV 1.1.1.1.1. + LV000001.3 + 130 + Leistungsverzeichnis + BD + + + 7.00 + + + + 100.00 + + + + VAT + S + 19.00 + + + 700.00 + + + + + + 01.02 + 01 + DETAIL + + + Pflasterfläche vorbereiten, Planum herstellen und verdichten + + + + 6.00 + + + + 250.00 + + + + VAT + S + 19.00 + + + 1500.00 + + + + + + 01 + GROUP + + + Summe 01 Bauabschnitt 1 - Vorarbeiten + + + + 000001 + + + 3600 + 1.0000 + + + + 1.00 + + + + VAT + S + 19.00 + + + 3600.00 + + + + + Kundenref. BT-10 + + 998877 + Musterbetrieb AG Demodaten + + HRA 45678 + + + Kontaktperson + + 5578 + + + absender@musterberieb.de + + + + 37079 + August-Spindler-Strasse 222 + Göttingen + DE + + + DE09687654321 + + + + 330145 + Auftraggeber Firmenkunde GmbH + + Herr Thomas Auftraggeber + + +49 321 456789 + + + thomas.auftraggeber@Firmenkunde.de + + + + 37073 + Gartenstraße 1212 + Göttingen + DE + + + DE1234567890 + + + + G12042-1-01 + + + BT-13 + + + Vertragsnr. BT-12 + + + Vergabenr. BT-17 + 50 + + + Projektnr. BT-11 + Project reference + + + + + Auftraggeber Firmenkunde GmbH + + 37073 + Gartenstraße 1212 + Göttingen + DE + + + + + 20260530 + + + + + EUR + + 58 + + DE75512108001245126199 + Musterbetrieb Kontoname + + + PBNKDEFF + + + + 684.00 + VAT + 3600.00 + S + 19.00 + + + + 20260513 + + + 20260530 + + + + Bei Zahlung bis zum 06.06.2026 zahlen Sie mit 2,50 % Skonto € 4.176,90 + + 20260606 + + + 4284.00 + 2.5 + + + + Bis zum zum 13.06.2026 ohne Abzug + + 20260613 + + + + 3600.00 + 0.00 + 0.00 + 3600.00 + 684.00 + 4284.00 + 0.00 + 4284.00 + + + Kostenstelle BT-19 + + + + diff --git a/library/src/test/resources/subinvoicelines/invalidSubInvoiceLineHierarchy.xml b/library/src/test/resources/subinvoicelines/invalidSubInvoiceLineHierarchy.xml new file mode 100644 index 00000000..89b6cd30 --- /dev/null +++ b/library/src/test/resources/subinvoicelines/invalidSubInvoiceLineHierarchy.xml @@ -0,0 +1,456 @@ + + + + + + + + + urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended + + + + 99877 + 380 + + 20260530 + + + Geschäftsführer: Herr Geschäftsführer , Muster Bau GmbH etc. + REG + + + Es bestehen Vereinbarungen, aus denen sich Minderungen des Entgelts ergeben können. + AAI + + + ZUGFeRD vers 2.4.0 Extended + ACB + + + Dies ist eine Beispiel-Rechnung zur empfohlenen Darstellung von Unterpositionen + ACB + + + + + + 0101 + 01 + DETAIL + + + 88888886349852 + 123456789 + 987654321 + Laser printer B/W + Schwarzweiß Laserdrucker + + + + 300.00 + + + + 2.00 + + + + VAT + S + 19.00 + + + 600.00 + + + + + + 0102 + 01 + DETAIL + + + 77777776349852 + 2345678910 + 876543219 + Ink printer color + Farbdrucker + + + + 150.00 + + + + 3.00 + + + + VAT + S + 19.00 + + + 450.00 + + + + + + 01 + GROUP + + + 6666656349852 + 345678912 + 765432198 + Subtotal hardware + Hardware Gesamt + + + + + 999.00 + + + + 1.00 + + + + VAT + S + 19.00 + + + + 999.00 + + + + + + 0201 + 02 + DETAIL + + + 55555556349852 + 456789123 + 654321987 + Toner + Toner + + + + 120.00 + + + + 3.00 + + + + VAT + S + 19.00 + + + 360.00 + + + + + + 0202 + 02 + DETAIL + + + 5555556349852 + 567891234 + 543219876 + PAPER + Kopierpapier + + + + 9.00 + + + + 10.00 + + + + VAT + S + 19.00 + + + 90.00 + + + + + + 02 + GROUP + + + 2222256349852 + 9345678912 + 9765432198 + Subtotal Accessories + Zubehör Gesamt + + + + 450.00 + + + + 1.00 + + + + VAT + S + 19.00 + + + 450.00 + + + + + Kundenref. BT-10 + + 998877 + Musterbetrieb Systemhaus AG + + HRA 45678 + + + Kontaktperson + + 5578 + + + absender@musterberieb.de + + + + 37079 + August-Müller-Strasse 222 + Göttingen + DE + + + DE09687654321 + + + + 330145 + Auftraggeber Firmenkunde GmbH + + Herr Thomas Auftraggeber + + +49 321 456789 + + + thomas.auftraggeber@Firmenkunde.de + + + + 37073 + Musterstraße 1212 + Göttingen + DE + + + DE1234567890 + + + + G12042-1-01 + + + BT-13 + + + Vertragsnr. BT-12 + + + Vergabenr. BT-17 + 50 + + + Projektnr. BT-11 + Project reference + + + + + Auftraggeber Firmenkunde GmbH + + 37073 + Musterstraße 1212 + Göttingen + DE + + + + + 20260530 + + + + + EUR + + 58 + + DE75512108001245126199 + Musterbetrieb Kontoname + + + PBNKDEFF + + + + 285.00 + VAT + 1500.00 + S + 19.00 + + + Bei Zahlung bis zum 06.06.2026 zahlen Sie mit 2,00 % Skonto € 1749,30 € + + 20260606 + + + 1785.00 + 2.00 + + + + Bis zum zum 13.06.2026 ohne Abzug + + 20260613 + + + + 1500.00 + 0.00 + 0.00 + 1500.00 + 285.00 + 1785.00 + 0.00 + 1785.00 + + + Kostenstelle BT-19 + + + + diff --git a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java index 5ca50de4..61565f61 100644 --- a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java @@ -5,6 +5,7 @@ import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.io.UncheckedIOException; +import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; @@ -24,6 +25,8 @@ import javax.xml.xpath.XPathFactory; import org.mustangproject.CalculatedInvoice; import org.mustangproject.XMLTools; +import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem; +import org.mustangproject.ZUGFeRD.LineCalculator; import org.mustangproject.ZUGFeRD.ZUGFeRDInvoiceImporter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -454,6 +457,9 @@ public class XMLValidator extends Validator { CalculatedInvoice ci=new CalculatedInvoice(); zi.extractInto(ci); + // check sub invoice line hierarchy if present + checkSubInvoiceLineHierarchy(ci, context); + } catch ( ArithmeticException e) { try { context.addResultItem(new ValidationResultItem(ESeverity.warning, "Arithmetical issue:"+e.getMessage()).setSection(10)); @@ -469,6 +475,77 @@ public class XMLValidator extends Validator { } + /*** + * validates that GROUP line totals match the sum of their DETAIL child lines + */ + private void checkSubInvoiceLineHierarchy(CalculatedInvoice invoice, ValidationContext context) { + IZUGFeRDExportableItem[] items = invoice.getZFItems(); + if (items == null || items.length == 0) { + return; + } + + // check if we have any sub invoice lines at all + boolean hasSubInvoiceLines = false; + for (IZUGFeRDExportableItem item : items) { + if (item.getLineStatusReasonCode() != null) { + hasSubInvoiceLines = true; + break; + } + } + if (!hasSubInvoiceLines) { + return; + } + + // build a map of line ID to item for quick lookup + java.util.HashMap itemMap = new java.util.HashMap<>(); + for (IZUGFeRDExportableItem item : items) { + if (item.getId() != null) { + itemMap.put(item.getId(), item); + } + } + + // for each GROUP line, sum up the DETAIL children and compare + for (IZUGFeRDExportableItem item : items) { + if ("GROUP".equals(item.getLineStatusReasonCode())) { + String groupId = item.getId(); + if (groupId == null) { + continue; + } + + // sum up direct DETAIL children + BigDecimal childSum = BigDecimal.ZERO; + for (IZUGFeRDExportableItem child : items) { + if (groupId.equals(child.getParentLineID()) && "DETAIL".equals(child.getLineStatusReasonCode())) { + LineCalculator lc = child.getCalculation(); + childSum = childSum.add(lc.getItemTotalNetAmount()); + } + } + + // also sum up nested GROUP children (their totals should already include their DETAIL children) + for (IZUGFeRDExportableItem child : items) { + if (groupId.equals(child.getParentLineID()) && "GROUP".equals(child.getLineStatusReasonCode())) { + LineCalculator lc = child.getCalculation(); + childSum = childSum.add(lc.getItemTotalNetAmount()); + } + } + + // compare with GROUP total + LineCalculator groupLc = item.getCalculation(); + BigDecimal groupTotal = groupLc.getItemTotalNetAmount(); + if (childSum.compareTo(groupTotal) != 0) { + try { + context.addResultItem(new ValidationResultItem(ESeverity.warning, + "Sub invoice line hierarchy mismatch: GROUP line " + groupId + + " has total " + groupTotal + " but sum of child lines is " + childSum) + .setSection(10)); + } catch (IrrecoverableValidationError ie) { + LOGGER.error(ie.getMessage(), ie); + } + } + } + } + } + public void validateXR(String xml, ESeverity errorImpact) throws IrrecoverableValidationError { //Guideline ID=urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_1.2 or diff --git a/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java b/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java index 7ed18b8f..47989968 100644 --- a/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java +++ b/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java @@ -373,4 +373,28 @@ public class XMLValidatorTest extends ResourceCase { } + public void testSubInvoiceLineHierarchy() { + final ValidationContext ctx = new ValidationContext(null); + final XMLValidator xv = new XMLValidator(ctx); + final XPathEngine xpath = new JAXPXPathEngine(); + + // test invalid hierarchy: GROUP sum does not match DETAIL children sum + // GROUP 01 has LineTotalAmount=999, but children sum to 1050 (600+450) + File tempFile = getResourceAsFile("invalidSubInvoiceLineHierarchy.xml"); + try { + xv.setFilename(tempFile.getAbsolutePath()); + xv.validate(); + + String s = "" + xv.getXMLResult() + ""; + // hierarchy mismatch should produce at least one warning + assertThat(s).valueByXPath("count(//warning)") + .asInt() + .isGreaterThanOrEqualTo(1); + + } catch (final IrrecoverableValidationError e) { + // ignore, will be in XML output anyway + } + + } + } diff --git a/validator/src/test/resources/invalidSubInvoiceLineHierarchy.xml b/validator/src/test/resources/invalidSubInvoiceLineHierarchy.xml new file mode 100644 index 00000000..89b6cd30 --- /dev/null +++ b/validator/src/test/resources/invalidSubInvoiceLineHierarchy.xml @@ -0,0 +1,456 @@ + + + + + + + + + urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended + + + + 99877 + 380 + + 20260530 + + + Geschäftsführer: Herr Geschäftsführer , Muster Bau GmbH etc. + REG + + + Es bestehen Vereinbarungen, aus denen sich Minderungen des Entgelts ergeben können. + AAI + + + ZUGFeRD vers 2.4.0 Extended + ACB + + + Dies ist eine Beispiel-Rechnung zur empfohlenen Darstellung von Unterpositionen + ACB + + + + + + 0101 + 01 + DETAIL + + + 88888886349852 + 123456789 + 987654321 + Laser printer B/W + Schwarzweiß Laserdrucker + + + + 300.00 + + + + 2.00 + + + + VAT + S + 19.00 + + + 600.00 + + + + + + 0102 + 01 + DETAIL + + + 77777776349852 + 2345678910 + 876543219 + Ink printer color + Farbdrucker + + + + 150.00 + + + + 3.00 + + + + VAT + S + 19.00 + + + 450.00 + + + + + + 01 + GROUP + + + 6666656349852 + 345678912 + 765432198 + Subtotal hardware + Hardware Gesamt + + + + + 999.00 + + + + 1.00 + + + + VAT + S + 19.00 + + + + 999.00 + + + + + + 0201 + 02 + DETAIL + + + 55555556349852 + 456789123 + 654321987 + Toner + Toner + + + + 120.00 + + + + 3.00 + + + + VAT + S + 19.00 + + + 360.00 + + + + + + 0202 + 02 + DETAIL + + + 5555556349852 + 567891234 + 543219876 + PAPER + Kopierpapier + + + + 9.00 + + + + 10.00 + + + + VAT + S + 19.00 + + + 90.00 + + + + + + 02 + GROUP + + + 2222256349852 + 9345678912 + 9765432198 + Subtotal Accessories + Zubehör Gesamt + + + + 450.00 + + + + 1.00 + + + + VAT + S + 19.00 + + + 450.00 + + + + + Kundenref. BT-10 + + 998877 + Musterbetrieb Systemhaus AG + + HRA 45678 + + + Kontaktperson + + 5578 + + + absender@musterberieb.de + + + + 37079 + August-Müller-Strasse 222 + Göttingen + DE + + + DE09687654321 + + + + 330145 + Auftraggeber Firmenkunde GmbH + + Herr Thomas Auftraggeber + + +49 321 456789 + + + thomas.auftraggeber@Firmenkunde.de + + + + 37073 + Musterstraße 1212 + Göttingen + DE + + + DE1234567890 + + + + G12042-1-01 + + + BT-13 + + + Vertragsnr. BT-12 + + + Vergabenr. BT-17 + 50 + + + Projektnr. BT-11 + Project reference + + + + + Auftraggeber Firmenkunde GmbH + + 37073 + Musterstraße 1212 + Göttingen + DE + + + + + 20260530 + + + + + EUR + + 58 + + DE75512108001245126199 + Musterbetrieb Kontoname + + + PBNKDEFF + + + + 285.00 + VAT + 1500.00 + S + 19.00 + + + Bei Zahlung bis zum 06.06.2026 zahlen Sie mit 2,00 % Skonto € 1749,30 € + + 20260606 + + + 1785.00 + 2.00 + + + + Bis zum zum 13.06.2026 ohne Abzug + + 20260613 + + + + 1500.00 + 0.00 + 0.00 + 1500.00 + 285.00 + 1785.00 + 0.00 + 1785.00 + + + Kostenstelle BT-19 + + + +