" // $NON-NLS-2$
+ DATE.udtFormat(trans.getDueDate())
@@ -902,12 +907,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if (trans.getInvoiceReferencedDocuments() != null) {
for (ReferencedDocument doc : trans.getInvoiceReferencedDocuments()) {
xml += ""
- + ""
- + XMLTools.encodeXML(doc.getIssuerAssignedID()) + "";
+ + ""
+ + XMLTools.encodeXML(doc.getIssuerAssignedID()) + "";
if (doc.getFormattedIssueDateTime() != null) {
xml += ""
- + DATE.qdtFormat(doc.getFormattedIssueDateTime())
- + "";
+ + DATE.qdtFormat(doc.getFormattedIssueDateTime())
+ + "";
}
xml += "";
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java b/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java
index c9ecc2a0..afd5ee28 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/model/TaxCategoryCodeTypeConstants.java
@@ -1,21 +1,23 @@
-/** **********************************************************************
- *
+/**
+ * *********************************************************************
+ *
* Copyright 2018 Jochen Staerk
- *
+ *
* Use is subject to license terms.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *
+ *
* See the License for the specific language governing permissions and
* limitations under the License.
- *
- *********************************************************************** */
+ *
+ * **********************************************************************
+ */
package org.mustangproject.ZUGFeRD.model;
import java.util.Set;
@@ -31,5 +33,5 @@ public class TaxCategoryCodeTypeConstants {
public static final String INTRACOMMUNITY = "K";
public static final String FREEEXPORT = "G";
- public static Set CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT, FREEEXPORT).collect(Collectors.toSet());
+ public static Set CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT, FREEEXPORT, UNTAXEDSERVICE).collect(Collectors.toSet());
}
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java
index 6d0a2664..9902a05c 100644
--- a/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/XRTest.java
@@ -25,6 +25,7 @@ import junit.framework.TestCase;
import org.mustangproject.*;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
+import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
import javax.xml.xpath.XPathExpressionException;
@@ -52,8 +53,8 @@ public class XRTest extends TestCase {
TradeParty recipient = new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE");
recipient.setEmail("quack@ducktown.org");
Invoice i = createInvoice(recipient);
- String legalOrgID="aCustomSellerLegalOrgId";
- String sellerID="aSellerTradePartyID";
+ String legalOrgID = "aCustomSellerLegalOrgId";
+ String sellerID = "aSellerTradePartyID";
i.getSender().setLegalOrganisation(new LegalOrganisation(legalOrgID));
i.getSender().setID(sellerID);
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
@@ -61,8 +62,8 @@ public class XRTest extends TestCase {
zf2p.generateXML(i);
String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8);
assertTrue(theXML.contains(""+sellerID+""));// must be possible without scheme #
- assertTrue(theXML.contains(""+legalOrgID+""));// must be possible without scheme #
+ assertTrue(theXML.contains("" + sellerID + ""));// must be possible without scheme #
+ assertTrue(theXML.contains("" + legalOrgID + ""));// must be possible without scheme #
assertThat(theXML).valueByXPath("count(//*[local-name()='IncludedSupplyChainTradeLineItem'])")
.asInt()
.isEqualTo(1); //2 errors are OK because there is a known bug
@@ -81,6 +82,7 @@ public class XRTest extends TestCase {
}
+
public void testXREdgeExport() {
// the writing part
@@ -100,7 +102,7 @@ public class XRTest extends TestCase {
.setReferenceNumber("991-01484-64")//leitweg-id
// not using any VAT, this is also a test of zero-rated goods:
.setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO).setTaxExemptionReason("Kleinunternehmer"), amount, new BigDecimal(1.0)))
- .setPayee( new TradeParty().setName("VR Factoring GmbH").setID("DE813838785").setLegalOrganisation(new LegalOrganisation("391200LDDFJDMIPPMZ54", "0199")))
+ .setPayee(new TradeParty().setName("VR Factoring GmbH").setID("DE813838785").setLegalOrganisation(new LegalOrganisation("391200LDDFJDMIPPMZ54", "0199")))
.embedFileInXML(fe1);
@@ -140,9 +142,9 @@ public class XRTest extends TestCase {
fail("ParseException not expected");
} catch (IOException e) {
fail("IOException not expected");
- }
- FileAttachment[] attachedFiles=readInvoice.getAdditionalReferencedDocuments();
- assertNotNull(attachedFiles);
+ }
+ FileAttachment[] attachedFiles = readInvoice.getAdditionalReferencedDocuments();
+ assertNotNull(attachedFiles);
assertEquals(attachedFiles.length, 1);
assertTrue(Arrays.equals(attachedFiles[0].getData(), b));
@@ -205,10 +207,40 @@ public class XRTest extends TestCase {
String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8);
assertThat(theXML).valueByXPath("count(//*[local-name()='ExemptionReason'])")
.asInt()
- .isEqualTo(1);
+ .isEqualTo(2);
}
+ public void testApplicablePercentInUntaxedService() {
+
+ // the writing part
+ TradeParty recipient = new TradeParty("Franz Müller", null, "55232", "Entenhausen", "DE");
+ String orgname = "Test company";
+ String number = "123";
+ String amountStr = "1.00";
+ BigDecimal amount = new BigDecimal(amountStr);
+ var i = new Invoice().setDueDate(new java.util.Date()).setIssueDate(new java.util.Date()).setDeliveryDate(new java.util.Date())
+ .setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("DE4711").addVATID("DE0815").setEmail("info@example.org").setContact(new org.mustangproject.Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new org.mustangproject.BankDetails("DE12500105170648489890", "COBADEFXXX")))
+ .setRecipient(recipient)
+ .setReferenceNumber("991-01484-64")//leitweg-id
+ // not using any VAT, this is also a test of zero-rated goods:
+ .setNumber(number).addItem(new org.mustangproject.Item(new org.mustangproject.Product("Testprodukt", "", "C62", java.math.BigDecimal.ZERO).setTaxCategoryCode(TaxCategoryCodeTypeConstants.UNTAXEDSERVICE).setTaxExemptionReason("Expemtion reason"), amount, new java.math.BigDecimal(1.0)));
+
+ ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
+ zf2p.setProfile(Profiles.getByName("XRechnung"));
+ zf2p.generateXML(i);
+ String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8);
+ // Untaxed services don't have the field RateApplicablePercent, since it would be always 0. An error is thrown on validation, if 0 is set.
+ assertThat(theXML).valueByXPath("count(//*[local-name()='RateApplicablePercent'])")
+ .asInt()
+ .isEqualTo(0);
+
+ //Exemption reason needs to be set if TaxCategoryCode == "O", reason should be at the product and in the ApplicableTradeTax
+ assertThat(theXML).valueByXPath("count(//*[local-name()='ExemptionReason'])")
+ .asInt()
+ .isEqualTo(2);
+ }
+
private org.mustangproject.Invoice createInvoice(TradeParty recipient) {
String orgname = "Test company";
String number = "123";