From d1200a8dcd93e393a6cc0c3a099b590b53f74fe5 Mon Sep 17 00:00:00 2001 From: Jens Heise Date: Wed, 6 May 2020 23:31:21 +0200 Subject: [PATCH 1/4] Bugfix in ZUGFeRD2PullProvider.generateXML(): Test for valid value of getDueDate() before using it or a NullPointerException might happen as 'hasDueDate==true' is not the result of a test to ensure that 'trans' overwrites 'getDueDate()' at all, so the default implementation from 'IZUGFeRDExportableTransaction' might get used which returns the unusable result 'null'. --- .../java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 34ce859e..c840303f 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -516,7 +516,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { } } - if (hasDueDate) { + if (hasDueDate && (trans.getDueDate()!=null)) { xml = xml + " " // $NON-NLS-2$ + zugferdDateFormat.format(trans.getDueDate()) + "\n";// 20130704 //$NON-NLS-1$ From 371cbb67a1e4c32bf2b760811c8f3d20185a8da1 Mon Sep 17 00:00:00 2001 From: Jens Heise Date: Thu, 7 May 2020 00:26:03 +0200 Subject: [PATCH 2/4] Bugfix in ZUGFeRD2PullProvider.generateXML(): Only Debit payment information is part of 'SpecifiedTradePaymentTerms' so test for 'payment' being an instance of 'IZUGFeRDTradeSettlementDebit' as 'IZUGFeRDTradeSettlement' and 'IZUGFeRDTradeSettlementPayment' return 'null' for 'getPaymentXML()' which is not allowed to be written to the XML file. --- .../java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index c840303f..76c43125 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -510,7 +510,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { if (trans.getTradeSettlement() != null) { for (IZUGFeRDTradeSettlement payment : trans.getTradeSettlement()) { - if (payment != null) { + if ((payment != null) && (payment instanceof IZUGFeRDTradeSettlementDebit)) { xml += payment.getPaymentXML(); } } From 1efd4ee9aea068bb6628dc38c06a6f8e2ae5a679 Mon Sep 17 00:00:00 2001 From: Jens Heise Date: Mon, 1 Jun 2020 20:34:00 +0200 Subject: [PATCH 3/4] Bugfix in ZF2ZInvoiceImporterTest: Make test work on case sensitive file systems The generated file is named "testout-ZF2new.pdf" not "testout-ZF2New.pdf" which will make the test fail on case sensitive file systems as can be found on many unix like systems. --- .../org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index 674766be..e99e683b 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -41,7 +41,7 @@ import junit.framework.TestSuite; * used for this import, testout-ZF2New.pdf */ public class ZF2ZInvoiceImporterTest extends TestCase { - final String TARGET_PDF = "./target/testout-ZF2New.pdf"; + final String TARGET_PDF = "./target/testout-ZF2new.pdf"; public void testInvoiceImport() { From 74900ebe69fc69a481a72576108f7a4b2409e364 Mon Sep 17 00:00:00 2001 From: Jens Heise Date: Tue, 2 Jun 2020 14:41:59 +0200 Subject: [PATCH 4/4] ZUGFeRD2PullProvider: Added several properties to be written to the ZUGFeRD-XML and if necessary corresponding methods in the IZUGFeRDExportable... interface objects of Transaction, Item and Product: Properties with new methods: - SubjectNote for 'ExchangedDocument.IncludedNote' (human readable document subject) - RebateAgreementExists for 'ExchangedDocument.IncludedNote' (Note that there are rebate agreements) - BasisQuantity (number of item units per price) - SellerAssignedID (seller identification of product) - BuyerAssignedID (buyer identification of product) - TaxExemptionReason (explanatory statement why no tax gets applied) enhancement to support other exemptions than "IC-supply" Properties for existing methods that did not get written to the XML up to now: - SellerTradeParty.ID (buyer assigned ID of seller) - SellerTradeParty.GlobalID of seller (e.g. DUNS) - BuyerOrderReferencedDocumentID (order number of buyer) --- .../ZUGFeRD/IZUGFeRDExportableItem.java | 11 ++- .../ZUGFeRD/IZUGFeRDExportableProduct.java | 25 +++++- .../IZUGFeRDExportableTransaction.java | 18 ++++ .../ZUGFeRD/ZUGFeRD2PullProvider.java | 86 ++++++++++++------- 4 files changed, 106 insertions(+), 34 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java index a4dfcc80..c4362443 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java @@ -47,12 +47,21 @@ public interface IZUGFeRDExportableItem { BigDecimal getPrice(); /** - * how many + * how many get billed * * @return the quantity of the item */ BigDecimal getQuantity(); + /** + * how many items units per price + * + * @return item units per price + */ + default BigDecimal getBasisQuantity() { + return BigDecimal.ONE.setScale(4); + } + default String getCategoryCode() { return TaxCategoryCodeTypeConstants.STANDARDRATE; } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java index ab441e74..197bbac9 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java @@ -75,6 +75,25 @@ public interface IZUGFeRDExportableProduct { */ String getDescription(); + /** + * Get the ID that had been assigned by the seller to + * identify the product + * + * @return seller assigned product ID + */ + default String getSellerAssignedID() { + return null; + } + + /** + * Get the ID that had been assigned by the buyer to + * identify the product + * + * @return buyer assigned product ID + */ + default String getBuyerAssignedID() { + return null; + } /** * VAT percent of the product (e.g. 19, or 5.1 if you like) * @@ -95,5 +114,9 @@ public interface IZUGFeRDExportableProduct { } } - + default String getTaxExemptionReason() { + if (isIntraCommunitySupply()) + return "Intra-community supply"; + return null; + } } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java index 920ab7d2..7cdbbe04 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java @@ -106,6 +106,16 @@ public interface IZUGFeRDExportableTransaction { } + /** + * subject of the document e.g. invoice and order + * number as human readable text + * + * @return string with document subject + */ + default String getSubjectNote() { + return null; + } + IZUGFeRDAllowanceCharge[] getZFAllowances(); @@ -272,6 +282,14 @@ public interface IZUGFeRDExportableTransaction { return null; } + /** + * returns if a rebate agreements exists + * + * @return + */ + default boolean rebateAgreementExists() { + return false; + } /** * get reference document number typically used for Invoice Corrections Will be added as IncludedNote in comfort profile diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 76c43125..d51a4b43 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -48,9 +48,10 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100)) .add(new BigDecimal(1)); priceGross = currentItem.getPrice().multiply(multiplicator); - totalGross = currentItem.getPrice().multiply(multiplicator).multiply(currentItem.getQuantity()); - itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).setScale(2, - BigDecimal.ROUND_HALF_UP); + totalGross = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity()) + .multiply(multiplicator); + itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity()) + .setScale(2, BigDecimal.ROUND_HALF_UP); itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount); } @@ -268,6 +269,20 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { } + String rebateAgreement = ""; + if (trans.rebateAgreementExists()) { + rebateAgreement = "\n" + " " + + "Es bestehen Rabatt- und Bonusvereinbarungen.\n" + + "AAK\n" + "\n"; + } + + String subjectNote = ""; + if (trans.getSubjectNote()!=null) { + subjectNote = "\n" + " " + + XMLTools.encodeXML(trans.getSubjectNote())+ "\n" + + "\n"; + } + String xml = "\n" //$NON-NLS-1$ + "\n" - // + " \n" - // + "Rechnung gemäß Bestellung Nr. 2013-471331 vom 01.03.2013.\n" - // + "\n" - // + " \n" - // + " \n" - // + " \n" - // + " \n" - // + "Es bestehen Rabatt- und Bonusvereinbarungen.\n" - // + " \n" - // + " AAK\n" - // + " \n" + + " \n" //$NON-NLS-1$ + " \n"; //$NON-NLS-1$ int lineID = 0; for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { lineID++; taxCategoryCode=currentItem.getProduct().getTaxCategoryCode(); - if (currentItem.getProduct().isIntraCommunitySupply()) { - exemptionReason="Intra-community supply"; + if (currentItem.getProduct().getTaxExemptionReason() != null) { + exemptionReason="" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + ""; } LineCalc lc = new LineCalc(currentItem); @@ -321,11 +327,17 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { " \n" //$NON-NLS-1$ + " " + lineID + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ + + " \n"; //$NON-NLS-1$ // + " 4012345001235\n" - // + " KR3M\n" - // + " 55T01\n" - + " " + XMLTools.encodeXML(currentItem.getProduct().getName()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + if (currentItem.getProduct().getSellerAssignedID() != null) { + xml = xml + " " + + XMLTools.encodeXML(currentItem.getProduct().getSellerAssignedID()) + "\n"; + } + if (currentItem.getProduct().getBuyerAssignedID() != null) { + xml = xml + " " + + XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "\n"; + } + xml = xml + " " + XMLTools.encodeXML(currentItem.getProduct().getName()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + " " + XMLTools.encodeXML(currentItem.getProduct().getDescription()) //$NON-NLS-1$ + "\n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ @@ -335,7 +347,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { + " " + priceFormat(lc.getPriceGross()) //$NON-NLS-1$ + "\n" //$NON-NLS-1$ //currencyID=\"EUR\" + " 1.0000\n" //$NON-NLS-1$ + + "\">" + quantityFormat(currentItem.getBasisQuantity()) +"\n" //$NON-NLS-1$ // + " \n" // + " false\n" // + " 0.6667\n" @@ -346,7 +358,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { + " " + priceFormat(currentItem.getPrice()) //$NON-NLS-1$ + "\n" //$NON-NLS-1$ // currencyID=\"EUR\" + " 1.0000\n" //$NON-NLS-1$ + + "\">" + quantityFormat(currentItem.getBasisQuantity()) +"\n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ @@ -381,9 +393,16 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { xml = xml + " " + XMLTools.encodeXML(trans.getReferenceNumber()) + "\n"; } - xml = xml + " \n" //$NON-NLS-1$ - // + " 4000001123452\n" - + " " + XMLTools.encodeXML(trans.getOwnOrganisationName()) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + xml = xml + " \n"; //$NON-NLS-1$ + if (trans.getOwnForeignOrganisationID()!=null) { + xml = xml + " " + XMLTools.encodeXML(trans.getOwnForeignOrganisationID()) + "\n"; + } + + if ((trans.getOwnContact()!=null)&&(trans.getOwnContact().getGlobalID()!=null)&&(trans.getOwnContact().getGlobalIDScheme()!=null)) { + xml = xml + " " + + XMLTools.encodeXML(trans.getOwnContact().getGlobalID()) + "\n"; + } + xml = xml + " " + XMLTools.encodeXML(trans.getOwnOrganisationName()) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ if ((trans.getOwnVATID()!=null)&&(trans.getOwnOrganisationName()!=null)) { @@ -429,12 +448,15 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { // + " 4000001987658\n" xml+=getContactAsXML(trans.getRecipient()); - xml += " \n" //$NON-NLS-1$ - // + " \n" - // + " 20130301\n" - // + " 2013-471331\n" - // + " \n" - + " \n" //$NON-NLS-1$ + xml += " \n"; //$NON-NLS-1$ + + if (trans.getBuyerOrderReferencedDocumentID()!=null) { + xml = xml + " \n" //$NON-NLS-1$ + + " " //$NON-NLS-1$ + + XMLTools.encodeXML(trans.getBuyerOrderReferencedDocumentID()) + "\n" //$NON-NLS-1$ + + " \n"; + } + xml = xml + " \n" //$NON-NLS-1$ + " \n" ; if (this.trans.getDeliveryAddress()!=null) { xml += ""+