diff --git a/README.md b/README.md index a8576f9..cf8daaa 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Add Gallop to your project via [Maven Central](https://central.sonatype.com/arti ```groovy dependencies { - implementation 'de.codebarista:gallop:2.0.0' + implementation 'de.codebarista:gallop:2.1.0' } ``` @@ -53,7 +53,7 @@ dependencies { de.codebarista gallop - 2.0.0 + 2.1.0 ``` @@ -153,7 +153,8 @@ public class InvoiceGenerator { .taxBasisTotalAmount(new BigDecimal("529.48")) // Tax basis total .taxTotalAmount(new BigDecimal("100.60")) // Total VAT amount .grandTotalAmount(new BigDecimal("630.08")) // Invoice total with VAT - .duePayableAmount(new BigDecimal("630.08")) // Amount due for payment + .paidAmount(new BigDecimal("100.00")) // Already paid amount + .duePayableAmount(new BigDecimal("530.08")) // Amount due for payment // Sales order reference .salesOrderReference("SO-98765"); @@ -167,6 +168,11 @@ public class InvoiceGenerator { ### Changelog +- 2.1.0: Add BT-30/BT-47 (Seller/Buyer legal registration identifier), + BT-32 (Seller tax registration identifier), + BT-33 (Seller additional legal information), + BT-113 (Paid amount) + and `NetAmount#getVatCategory` - 2.0.0: Gallop no longer relies on lombok, introduce fluent api - 1.0.1: Add action to publish to maven central - 1.0.0: Initial version diff --git a/build.gradle b/build.gradle index 441e62e..ebcc184 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,13 @@ plugins { } group = 'de.codebarista' -version = '2.0.0' +version = '2.1.0' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} repositories { mavenCentral() @@ -59,7 +65,11 @@ mavenPublishing { } publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) - signAllPublications() + + // Only sign if publishing to Maven Central (not for local) + if (project.hasProperty("signingInMemoryKeyId") || project.hasProperty("signing.keyId")) { + signAllPublications() + } } tasks.register('printVersion') { diff --git a/src/main/java/de/codebarista/gallop/xrechnung/XRechnungWriter.java b/src/main/java/de/codebarista/gallop/xrechnung/XRechnungWriter.java index af03050..3538bcc 100644 --- a/src/main/java/de/codebarista/gallop/xrechnung/XRechnungWriter.java +++ b/src/main/java/de/codebarista/gallop/xrechnung/XRechnungWriter.java @@ -220,12 +220,26 @@ private Element createTradeHeader(XmlDocumentBuilder builder) { Element seller = builder.createElement(NS_RAM, "SellerTradeParty"); tradeHeader.appendChild(seller); seller.appendChild(createName(builder, sellerInfo.getName())); + if (XRechnungUtils.isNotNullOrBlank(sellerInfo.getSellerAdditionalLegalInfo())) { + seller.appendChild(createDescription(builder, sellerInfo.getSellerAdditionalLegalInfo())); + } + if (XRechnungUtils.isNotNullOrBlank(sellerInfo.getLegalRegistrationIdentifier())) { + Element specifiedLegalOrganization = builder.createElement(NS_RAM, "SpecifiedLegalOrganization"); + specifiedLegalOrganization.appendChild( + createID(builder, + sellerInfo.getLegalRegistrationIdentifier(), + sellerInfo.getLegalRegistrationIdentifierScheme())); + seller.appendChild(specifiedLegalOrganization); + } seller.appendChild(createTradeContact(builder, sellerInfo.getContact())); seller.appendChild(createAddress(builder, sellerInfo.getAddress())); seller.appendChild(createElectronicAddressEmailElement(builder, sellerInfo.getElectronicAddress())); if (XRechnungUtils.isNotNullOrBlank(sellerInfo.getVatId())) { seller.appendChild(createTaxRegistration(builder, "VA", sellerInfo.getVatId())); } + if (XRechnungUtils.isNotNullOrBlank(sellerInfo.getSellerTaxRegistrationIdentifier())) { + seller.appendChild(createTaxRegistration(builder, "FC", sellerInfo.getSellerTaxRegistrationIdentifier())); + } } SellerOrBuyer buyerInfo = invoice.getBuyer(); @@ -233,6 +247,14 @@ private Element createTradeHeader(XmlDocumentBuilder builder) { Element buyer = builder.createElement(NS_RAM, "BuyerTradeParty"); tradeHeader.appendChild(buyer); buyer.appendChild(createName(builder, buyerInfo.getName())); + if (XRechnungUtils.isNotNullOrBlank(buyerInfo.getLegalRegistrationIdentifier())) { + Element specifiedLegalOrganization = builder.createElement(NS_RAM, "SpecifiedLegalOrganization"); + specifiedLegalOrganization.appendChild( + createID(builder, + buyerInfo.getLegalRegistrationIdentifier(), + buyerInfo.getLegalRegistrationIdentifierScheme())); + buyer.appendChild(specifiedLegalOrganization); + } buyer.appendChild(createAddress(builder, buyerInfo.getAddress())); buyer.appendChild(createElectronicAddressEmailElement(builder, buyerInfo.getElectronicAddress())); if (XRechnungUtils.isNotNullOrBlank(buyerInfo.getVatId())) { @@ -343,6 +365,11 @@ private Element createTradeSettlement(XmlDocumentBuilder builder) { grandTotal.setTextContent(invoice.getGrandTotalAmount().toString()); } sum.appendChild(grandTotal); + if (invoice.getPaidAmount() != null) { + Element totalPrepaid = builder.createElement(NS_RAM, "TotalPrepaidAmount"); // BT-113 + totalPrepaid.setTextContent(invoice.getPaidAmount().toString()); + sum.appendChild(totalPrepaid); + } Element duePayable = builder.createElement(NS_RAM, "DuePayableAmount"); if (invoice.getDuePayableAmount() != null) { duePayable.setTextContent(invoice.getDuePayableAmount().toString()); @@ -472,8 +499,15 @@ private Element createCharge(XmlDocumentBuilder builder, Charge charge) { } private static Element createID(XmlDocumentBuilder builder, String id) { + return createID(builder, id, null); + } + + private static Element createID(XmlDocumentBuilder builder, String id, String schemeID) { Element element = builder.createElement(NS_RAM, "ID"); element.setTextContent(id); + if (XRechnungUtils.isNotNullOrBlank(schemeID)) { + element.setAttribute("schemeID", schemeID); + } return element; } @@ -506,9 +540,7 @@ private static Element createDateTimeString(XmlDocumentBuilder builder, OffsetDa private static Element createTaxRegistration(XmlDocumentBuilder builder, String scheme, String id) { Element element = builder.createElement(NS_RAM, "SpecifiedTaxRegistration"); - Element idElement = createID(builder, id); - idElement.setAttribute("schemeID", scheme); - element.appendChild(idElement); + element.appendChild(createID(builder, id, scheme)); return element; } diff --git a/src/main/java/de/codebarista/gallop/xrechnung/model/Allowance.java b/src/main/java/de/codebarista/gallop/xrechnung/model/Allowance.java index a745e81..1463fba 100644 --- a/src/main/java/de/codebarista/gallop/xrechnung/model/Allowance.java +++ b/src/main/java/de/codebarista/gallop/xrechnung/model/Allowance.java @@ -83,6 +83,7 @@ public BigDecimal getNetAmount() { /** * Gets the {@link #vatCategory}. */ + @Override public TaxCategory getVatCategory() { return vatCategory; } diff --git a/src/main/java/de/codebarista/gallop/xrechnung/model/Charge.java b/src/main/java/de/codebarista/gallop/xrechnung/model/Charge.java index f3f59c3..4439cd3 100644 --- a/src/main/java/de/codebarista/gallop/xrechnung/model/Charge.java +++ b/src/main/java/de/codebarista/gallop/xrechnung/model/Charge.java @@ -80,6 +80,7 @@ public BigDecimal getNetAmount() { return netAmount; } + @Override public TaxCategory getVatCategory() { return vatCategory; } diff --git a/src/main/java/de/codebarista/gallop/xrechnung/model/Invoice.java b/src/main/java/de/codebarista/gallop/xrechnung/model/Invoice.java index e24bd6a..de3e47a 100644 --- a/src/main/java/de/codebarista/gallop/xrechnung/model/Invoice.java +++ b/src/main/java/de/codebarista/gallop/xrechnung/model/Invoice.java @@ -104,6 +104,11 @@ public class Invoice { */ private BigDecimal grandTotalAmount; + /** + * Sum of the amount that has already been paid (BT-113) + */ + private BigDecimal paidAmount; + /** * Amount due for payment (BT-115) */ @@ -333,6 +338,14 @@ public Invoice grandTotalAmount(BigDecimal grandTotalAmount) { return this; } + /** + * Sets the {@link #paidAmount} + */ + public Invoice paidAmount(BigDecimal paidAmount) { + this.paidAmount = paidAmount; + return this; + } + /** * Sets the {@link #duePayableAmount} */ @@ -544,6 +557,13 @@ public BigDecimal getGrandTotalAmount() { return grandTotalAmount; } + /** + * Gets the {@link #paidAmount} + */ + public BigDecimal getPaidAmount() { + return paidAmount; + } + /** * Gets the {@link #duePayableAmount}. */ diff --git a/src/main/java/de/codebarista/gallop/xrechnung/model/Item.java b/src/main/java/de/codebarista/gallop/xrechnung/model/Item.java index 4f79020..09382ec 100644 --- a/src/main/java/de/codebarista/gallop/xrechnung/model/Item.java +++ b/src/main/java/de/codebarista/gallop/xrechnung/model/Item.java @@ -256,6 +256,11 @@ public BigDecimal getVatRate() { return vat.getRate(); } + @Override + public TaxCategory getVatCategory() { + return vat.getCategory(); + } + /** * Gets the {@link #sellerAssignedId}. */ diff --git a/src/main/java/de/codebarista/gallop/xrechnung/model/NetAmount.java b/src/main/java/de/codebarista/gallop/xrechnung/model/NetAmount.java index 38a7e13..8f2f46a 100644 --- a/src/main/java/de/codebarista/gallop/xrechnung/model/NetAmount.java +++ b/src/main/java/de/codebarista/gallop/xrechnung/model/NetAmount.java @@ -29,4 +29,9 @@ public interface NetAmount { * @return the vat rate as a {@link BigDecimal} */ BigDecimal getVatRate(); + + /** + * Returns the vat category. + */ + TaxCategory getVatCategory(); } diff --git a/src/main/java/de/codebarista/gallop/xrechnung/model/SellerOrBuyer.java b/src/main/java/de/codebarista/gallop/xrechnung/model/SellerOrBuyer.java index b659be0..2d8d012 100644 --- a/src/main/java/de/codebarista/gallop/xrechnung/model/SellerOrBuyer.java +++ b/src/main/java/de/codebarista/gallop/xrechnung/model/SellerOrBuyer.java @@ -10,6 +10,7 @@ public class SellerOrBuyer { * The official/legal name under which the seller/buyer can be found. */ private String name; + /** * Seller/Buyer trading name (BT-28/BT-45) *

@@ -17,11 +18,50 @@ public class SellerOrBuyer { */ private String tradingName; + /** + * Seller/Buyer legal registration identifier (BT-30/BT-47) + *

+ * An identifier issued by an official registration authority that identifies the seller/buyer + * as a legal entity or legal person. + */ + private String legalRegistrationIdentifier; + + /** + * Seller/Buyer legal registration identifier scheme for (BT-30/BT-47) + *

+ * A code from ISO/IEC 17 6523 + * that describes the schema/type of the legal registration identifier. + *

+ * No schema is set for BT-30 if this is null or empty. + */ + private String legalRegistrationIdentifierScheme; + /** * Seller/Buyer VAT identifier (BT-31/BT-48) */ private String vatId; + /** + * Seller tax registration identifier (BT-32) + *

+ * A local tax identification of the seller (determined by their address) + * or a reference to their registered tax status. + * (If applicable, the indication "reverse charge" or the VAT exemption of + * the invoice issuer should be entered here.) + *

+ * Usually the Tax-ID. + *

+ * Only necessary if VAT identifier (BT-31) is not present. + */ + private String sellerTaxRegistrationIdentifier; + + /** + * Seller additional legal information (BT-33) + *

+ * Additional legal information that is relevant for the seller (such as share capital). + */ + private String sellerAdditionalLegalInfo; + /** * Seller/Buyer electronic address (BT-34/BT-49) */ @@ -89,6 +129,38 @@ public SellerOrBuyer vatId(String vatId) { return this; } + /** + * Sets the {@link #sellerTaxRegistrationIdentifier}. + */ + public SellerOrBuyer sellerTaxRegistrationIdentifier(String taxId) { + this.sellerTaxRegistrationIdentifier = taxId; + return this; + } + + /** + * Sets the {@link #legalRegistrationIdentifier}. + */ + public SellerOrBuyer legalRegistrationIdentifier(String legalRegistrationIdentifier) { + this.legalRegistrationIdentifier = legalRegistrationIdentifier; + return this; + } + + /** + * Sets the {@link #legalRegistrationIdentifierScheme}. + */ + public SellerOrBuyer legalRegistrationIdentifierScheme(String legalRegistrationIdentifierScheme) { + this.legalRegistrationIdentifierScheme = legalRegistrationIdentifierScheme; + return this; + } + + /** + * Sets the {@link #sellerAdditionalLegalInfo}. + */ + public SellerOrBuyer sellerAdditionalLegalInfo(String info) { + this.sellerAdditionalLegalInfo = info; + return this; + } + /** * Sets the {@link #electronicAddress}. */ @@ -142,6 +214,34 @@ public String getVatId() { return vatId; } + /** + * Gets the {@link #sellerTaxRegistrationIdentifier} + */ + public String getSellerTaxRegistrationIdentifier() { + return sellerTaxRegistrationIdentifier; + } + + /** + * Gets the {@link #legalRegistrationIdentifier} + */ + public String getLegalRegistrationIdentifier() { + return legalRegistrationIdentifier; + } + + /** + * Gets the {@link #legalRegistrationIdentifierScheme} + */ + public String getLegalRegistrationIdentifierScheme() { + return legalRegistrationIdentifierScheme; + } + + /** + * Gets the {@link #sellerAdditionalLegalInfo} + */ + public String getSellerAdditionalLegalInfo() { + return sellerAdditionalLegalInfo; + } + /** * Gets the {@link #electronicAddress}. */ diff --git a/src/test/java/de/codebarista/gallop/xrechnung/BuildInvoiceTest.java b/src/test/java/de/codebarista/gallop/xrechnung/BuildInvoiceTest.java index 208a510..1fd128d 100644 --- a/src/test/java/de/codebarista/gallop/xrechnung/BuildInvoiceTest.java +++ b/src/test/java/de/codebarista/gallop/xrechnung/BuildInvoiceTest.java @@ -116,7 +116,8 @@ public void buildInvoice() { .taxBasisTotalAmount(new BigDecimal("529.48")) // Tax basis total .taxTotalAmount(new BigDecimal("100.60")) // Total VAT amount .grandTotalAmount(new BigDecimal("630.08")) // Invoice total with VAT - .duePayableAmount(new BigDecimal("630.08")) // Amount due for payment + .paidAmount(new BigDecimal("100.00")) // Already paid amount + .duePayableAmount(new BigDecimal("530.08")) // Amount due for payment // Sales order reference .salesOrderReference("SO-98765"); diff --git a/src/test/java/de/codebarista/gallop/xrechnung/XRechnungWriterScenariosTest.java b/src/test/java/de/codebarista/gallop/xrechnung/XRechnungWriterScenariosTest.java index 471cb34..6a8c28e 100644 --- a/src/test/java/de/codebarista/gallop/xrechnung/XRechnungWriterScenariosTest.java +++ b/src/test/java/de/codebarista/gallop/xrechnung/XRechnungWriterScenariosTest.java @@ -48,7 +48,10 @@ public class XRechnungWriterScenariosTest { "order_with_paypal_direct_debit", "order_with_paypal_invoice", "order_with_shipping_costs_with_multiple_taxes", - "order_with_tax_free_product" + "order_with_tax_free_product", + "order_with_already_paid_amount", + "order_without_vatid", + "order_with_legal_registration_identifiers" }) public void writeXRechnung(String testFile) throws ParserConfigurationException, TransformerException { TestHelper testHelper = new TestHelper("invoice"); diff --git a/src/test/resources/invoice/order_with_already_paid_amount/invoice.json b/src/test/resources/invoice/order_with_already_paid_amount/invoice.json new file mode 100644 index 0000000..e255e57 --- /dev/null +++ b/src/test/resources/invoice/order_with_already_paid_amount/invoice.json @@ -0,0 +1,121 @@ +{ + "documentTypeCode": "380", + "documentId": "1012", + "leitwegId": null, + "currency": "EUR", + "paymentInstructions": { + "meansType": "10", + "meansText": "Cash on delivery", + "remittanceInfo": null, + "paymentTerms": "Die Ware bleibt, bis zur vollständigen Bezahlung, unser Eigentum.\nLeistungsdatum entspricht Rechnungsdatum", + "creditTransfers": [], + "paymentCardInformation": null, + "directDebit": null + }, + "issueDate": "2024-11-30T13:12:11.781+00:00", + "seller": { + "name": "Example Company", + "tradingName": "Examply Company Doing Things", + "vatId": "DE987654321", + "electronicAddress": "mail@company.com", + "electronicAddressScheme": "EM", + "address": { + "addressLineOne": "Tribute Avenue 777", + "addressLineTwo": null, + "addressLineThree": null, + "city": "Taxora", + "zipCode": "12345", + "countryIsoCode": "DE" + }, + "contact": { + "name": "Kim Elliot", + "phone": "123456789", + "email": "mail@company.com" + } + }, + "buyer": { + "name": "Test Test", + "tradingName": null, + "vatId": null, + "electronicAddress": "test@test.test", + "electronicAddressScheme": null, + "address": { + "addressLineOne": "Test", + "addressLineTwo": null, + "addressLineThree": null, + "city": "Foo", + "zipCode": "11223", + "countryIsoCode": "BH" + }, + "contact": null + }, + "deliveryInfo": { + "name": "Test Test", + "deliveryAddress": { + "addressLineOne": "Test", + "addressLineTwo": null, + "addressLineThree": null, + "city": "Foo", + "zipCode": "11223", + "countryIsoCode": "BH" + }, + "actualDeliveryDate": null + }, + "items": [ + { + "id": 1, + "quantity": 1, + "unitCode": "XPP", + "itemTotalNetAmount": 16.80, + "name": "Main product with properties", + "description": null, + "unitPrice": 16.8000, + "vat": { + "rate": 19, + "category": "S", + "taxableAmount": null, + "taxAmount": null, + "vatExemptionReasonText": null, + "vatExemptionReasonCode": null + }, + "sellerAssignedId": "10007.1", + "itemAttributes": [ + { + "name": "Size", + "value": "S" + } + ], + "netAmount": 16.80 + } + ], + "vatTotals": [ + { + "rate": 19, + "category": "S", + "taxableAmount": 16.80, + "taxAmount": 3.19, + "vatExemptionReasonText": null, + "vatExemptionReasonCode": null + } + ], + "precedingInvoiceReferences": [], + "lineTotalAmount": 16.80, + "allowanceTotalAmount": 0.00, + "chargeTotalAmount": 0.00, + "taxBasisTotalAmount": 16.80, + "taxTotalAmount": 3.19, + "grandTotalAmount": 19.99, + "paidAmount": 9.99, + "duePayableAmount": 10.00, + "salesOrderReference": "10000", + "invoiceNotes": [], + "allowances": [], + "charges": [ + { + "netAmount": 0.00, + "vatCategory": "S", + "vatRate": 19, + "reason": "Shipping costs" + } + ] +} diff --git a/src/test/resources/invoice/order_with_already_paid_amount/xrechnung.xml b/src/test/resources/invoice/order_with_already_paid_amount/xrechnung.xml new file mode 100644 index 0000000..77e25c7 --- /dev/null +++ b/src/test/resources/invoice/order_with_already_paid_amount/xrechnung.xml @@ -0,0 +1,147 @@ + + + + + urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 + + + urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 + + + + 1012 + 380 + + 20241130 + + + + + + 1 + + + 10007.1 + Main product with properties + + Size + S + + + + + 16.8000 + 1 + + + + 1 + + + + VAT + S + 19 + + + 16.80 + + + + + N/A + + Example Company + + Kim Elliot + + 123456789 + + + mail@company.com + + + + 12345 + Tribute Avenue 777 + Taxora + DE + + + mail@company.com + + + DE987654321 + + + + Test Test + + 11223 + Test + Foo + BH + + + test@test.test + + + + 10000 + + + + + Test Test + + 11223 + Test + Foo + BH + + + + + EUR + + 10 + Cash on delivery + + + 3.19 + VAT + 16.80 + S + 19 + + + + true + + 0.00 + Shipping costs + + VAT + S + 19 + + + + Die Ware bleibt, bis zur vollständigen Bezahlung, unser Eigentum. +Leistungsdatum entspricht Rechnungsdatum + + + 16.80 + 0.00 + 0.00 + 16.80 + 3.19 + 19.99 + 9.99 + 10.00 + + + + diff --git a/src/test/resources/invoice/order_with_legal_registration_identifiers/invoice.json b/src/test/resources/invoice/order_with_legal_registration_identifiers/invoice.json new file mode 100644 index 0000000..dd4a1e7 --- /dev/null +++ b/src/test/resources/invoice/order_with_legal_registration_identifiers/invoice.json @@ -0,0 +1,125 @@ +{ + "documentTypeCode": "380", + "documentId": "1013", + "leitwegId": null, + "currency": "EUR", + "paymentInstructions": { + "meansType": "58", + "meansText": null, + "remittanceInfo": "RE-2024-0042", + "paymentTerms": "Zahlung innerhalb von 30 Tagen nach Erhalt der Rechnung.", + "creditTransfers": [ + { + "iban": "DE86500105173557491398", + "accountName": "Firmenkonto Beispiel GmbH", + "bic": "AAAAZZZ0BBB" + } + ], + "paymentCardInformation": null, + "directDebit": null + }, + "issueDate": "2024-12-07T10:33:25.540+00:00", + "seller": { + "name": "Beispiel GmbH", + "tradingName": "Beispiel Handelsgesellschaft", + "legalRegistrationIdentifier": "555444333", + "legalRegistrationIdentifierScheme": "0060", + "vatId": "DE987654321", + "electronicAddress": "info@beispiel-gmbh.de", + "electronicAddressScheme": "EM", + "address": { + "addressLineOne": "Musterstraße 42", + "addressLineTwo": null, + "addressLineThree": null, + "city": "Berlin", + "zipCode": "10115", + "countryIsoCode": "DE" + }, + "contact": { + "name": "Max Mustermann", + "phone": "030123456789", + "email": "kontakt@beispiel-gmbh.de" + } + }, + "buyer": { + "name": "Gerhard Gewerbetreibender", + "tradingName": null, + "legalRegistrationIdentifier": "4000000123456", + "legalRegistrationIdentifierScheme": "0088", + "vatId": "DE123456789", + "electronicAddress": "gerhard@gerhards-gmbh.de", + "electronicAddressScheme": null, + "address": { + "addressLineOne": "Gerhardstraße", + "addressLineTwo": null, + "addressLineThree": null, + "city": "Großgerau", + "zipCode": "64521", + "countryIsoCode": "DE" + }, + "contact": null + }, + "deliveryInfo": { + "name": "Gerhard Gewerbetreibender", + "deliveryAddress": { + "addressLineOne": "Gerhardstraße", + "addressLineTwo": null, + "addressLineThree": null, + "city": "Großgerau", + "zipCode": "64521", + "countryIsoCode": "DE" + }, + "actualDeliveryDate": null + }, + "items": [ + { + "id": 1, + "quantity": 1, + "unitCode": "XPP", + "itemTotalNetAmount": 416.76, + "name": "Hauptartikel", + "description": null, + "unitPrice": 416.7600, + "vat": { + "rate": 19, + "category": "S", + "taxableAmount": null, + "taxAmount": null, + "vatExemptionReasonText": null, + "vatExemptionReasonCode": null + }, + "sellerAssignedId": "10001", + "itemAttributes": [], + "netAmount": 416.76 + } + ], + "vatTotals": [ + { + "rate": 19, + "category": "S", + "taxableAmount": 416.76, + "taxAmount": 79.19, + "vatExemptionReasonText": null, + "vatExemptionReasonCode": null + } + ], + "precedingInvoiceReferences": [], + "lineTotalAmount": 416.76, + "allowanceTotalAmount": 0.00, + "chargeTotalAmount": 0.00, + "taxBasisTotalAmount": 416.76, + "taxTotalAmount": 79.19, + "grandTotalAmount": 495.95, + "duePayableAmount": 495.95, + "salesOrderReference": "10011", + "invoiceNotes": [], + "allowances": [], + "charges": [ + { + "netAmount": 0.00, + "vatCategory": "S", + "vatRate": 19, + "reason": "Versandkosten" + } + ] +} diff --git a/src/test/resources/invoice/order_with_legal_registration_identifiers/xrechnung.xml b/src/test/resources/invoice/order_with_legal_registration_identifiers/xrechnung.xml new file mode 100644 index 0000000..6c64440 --- /dev/null +++ b/src/test/resources/invoice/order_with_legal_registration_identifiers/xrechnung.xml @@ -0,0 +1,157 @@ + + + + + urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 + + + urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 + + + + 1013 + 380 + + 20241207 + + + + + + 1 + + + 10001 + Hauptartikel + + + + 416.7600 + 1 + + + + 1 + + + + VAT + S + 19 + + + 416.76 + + + + + N/A + + Beispiel GmbH + + 555444333 + + + Max Mustermann + + 030123456789 + + + kontakt@beispiel-gmbh.de + + + + 10115 + Musterstraße 42 + Berlin + DE + + + info@beispiel-gmbh.de + + + DE987654321 + + + + Gerhard Gewerbetreibender + + 4000000123456 + + + 64521 + Gerhardstraße + Großgerau + DE + + + gerhard@gerhards-gmbh.de + + + DE123456789 + + + + 10011 + + + + + Gerhard Gewerbetreibender + + 64521 + Gerhardstraße + Großgerau + DE + + + + + RE-2024-0042 + EUR + + 58 + + DE86500105173557491398 + Firmenkonto Beispiel GmbH + + + AAAAZZZ0BBB + + + + 79.19 + VAT + 416.76 + S + 19 + + + + true + + 0.00 + Versandkosten + + VAT + S + 19 + + + + Zahlung innerhalb von 30 Tagen nach Erhalt der Rechnung. + + + 416.76 + 0.00 + 0.00 + 416.76 + 79.19 + 495.95 + 495.95 + + + + diff --git a/src/test/resources/invoice/order_without_vatid/invoice.json b/src/test/resources/invoice/order_without_vatid/invoice.json new file mode 100644 index 0000000..6b6a5e9 --- /dev/null +++ b/src/test/resources/invoice/order_without_vatid/invoice.json @@ -0,0 +1,117 @@ +{ + "documentTypeCode": "380", + "documentId": "1032", + "leitwegId": null, + "currency": "EUR", + "paymentInstructions": { + "meansType": "10", + "meansText": "Cash on delivery", + "remittanceInfo": null, + "paymentTerms": "Die Ware bleibt, bis zur vollständigen Bezahlung, unser Eigentum.\nLeistungsdatum entspricht Rechnungsdatum", + "creditTransfers": [], + "paymentCardInformation": null, + "directDebit": null + }, + "issueDate": "2024-12-16T11:28:15.698+00:00", + "seller": { + "name": "Test Gbr", + "tradingName": null, + "sellerTaxRegistrationIdentifier": "123/456/789", + "legalRegistrationIdentifier": "123/456/789", + "sellerAdditionalLegalInfo": "Kein Ausweis von Umsatzsteuer, da Kleinunternehmer gemäß § 19 UStG", + "electronicAddress": "info@kleinunternehmer.de", + "electronicAddressScheme": "EM", + "address": { + "addressLineOne": "Teststraße 42", + "addressLineTwo": null, + "addressLineThree": null, + "city": "Testdorf", + "zipCode": "12123", + "countryIsoCode": "DE" + }, + "contact": { + "name": "Uwe Klein", + "phone": "0123456/789", + "email": "ceo@kleinunternehmer.de" + } + }, + "buyer": { + "name": "Testonia Test", + "tradingName": null, + "vatId": null, + "electronicAddress": "test@test.test", + "electronicAddressScheme": null, + "address": { + "addressLineOne": "Teststreet", + "addressLineTwo": null, + "addressLineThree": null, + "city": "Testing", + "zipCode": "12345", + "countryIsoCode": "DE" + }, + "contact": null + }, + "deliveryInfo": { + "name": "Testonia Test", + "deliveryAddress": { + "addressLineOne": "Teststreet", + "addressLineTwo": null, + "addressLineThree": null, + "city": "Testing", + "zipCode": "12345", + "countryIsoCode": "DE" + }, + "actualDeliveryDate": null + }, + "items": [ + { + "id": 1, + "quantity": 1, + "unitCode": "XPP", + "itemTotalNetAmount": 100.00, + "name": "Tax free product", + "description": null, + "unitPrice": 100.0000, + "vat": { + "rate": 0, + "category": "E", + "taxableAmount": null, + "taxAmount": null, + "vatExemptionReasonText": null, + "vatExemptionReasonCode": null + }, + "sellerAssignedId": "SW10002", + "itemAttributes": [], + "netAmount": 100.00 + } + ], + "vatTotals": [ + { + "rate": 0, + "category": "E", + "taxableAmount": 105.00, + "taxAmount": 0.00, + "vatExemptionReasonText": "Kein Ausweis von Umsatzsteuer, da Kleinunternehmer gemäß § 19 UStG", + "vatExemptionReasonCode": null + } + ], + "precedingInvoiceReferences": [], + "lineTotalAmount": 100.00, + "allowanceTotalAmount": 0.00, + "chargeTotalAmount": 5.00, + "taxBasisTotalAmount": 105.00, + "taxTotalAmount": 0.00, + "grandTotalAmount": 105.00, + "duePayableAmount": 105.00, + "salesOrderReference": "10013", + "invoiceNotes": [], + "allowances": [], + "charges": [ + { + "netAmount": 5.00, + "vatCategory": "E", + "vatRate": 0, + "reason": "Versandkosten" + } + ] +} diff --git a/src/test/resources/invoice/order_without_vatid/xrechnung.xml b/src/test/resources/invoice/order_without_vatid/xrechnung.xml new file mode 100644 index 0000000..8d548b1 --- /dev/null +++ b/src/test/resources/invoice/order_without_vatid/xrechnung.xml @@ -0,0 +1,147 @@ + + + + + urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 + + + urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 + + + + 1032 + 380 + + 20241216 + + + + + + 1 + + + SW10002 + Tax free product + + + + 100.0000 + 1 + + + + 1 + + + + VAT + E + 0 + + + 100.00 + + + + + N/A + + Test Gbr + Kein Ausweis von Umsatzsteuer, da Kleinunternehmer gemäß § 19 UStG + + 123/456/789 + + + Uwe Klein + + 0123456/789 + + + ceo@kleinunternehmer.de + + + + 12123 + Teststraße 42 + Testdorf + DE + + + info@kleinunternehmer.de + + + 123/456/789 + + + + Testonia Test + + 12345 + Teststreet + Testing + DE + + + test@test.test + + + + 10013 + + + + + Testonia Test + + 12345 + Teststreet + Testing + DE + + + + + EUR + + 10 + Cash on delivery + + + 0.00 + VAT + Kein Ausweis von Umsatzsteuer, da Kleinunternehmer gemäß § 19 UStG + 105.00 + E + 0 + + + + true + + 5.00 + Versandkosten + + VAT + E + 0 + + + + Die Ware bleibt, bis zur vollständigen Bezahlung, unser Eigentum. +Leistungsdatum entspricht Rechnungsdatum + + + 100.00 + 5.00 + 0.00 + 105.00 + 0.00 + 105.00 + 105.00 + + + +