diff --git a/library/src/main/java/org/mustangproject/Invoice.java b/library/src/main/java/org/mustangproject/Invoice.java index 42490ed1..3622b041 100644 --- a/library/src/main/java/org/mustangproject/Invoice.java +++ b/library/src/main/java/org/mustangproject/Invoice.java @@ -63,6 +63,7 @@ public class Invoice implements IExportableTransaction { protected String specifiedProcuringProjectID = null; protected String specifiedProcuringProjectName = null; protected String despatchAdviceReferencedDocumentID = null; + protected String vatDueDateTypeCode = null; public Invoice() { ZFItems = new ArrayList<>(); @@ -703,4 +704,18 @@ public class Invoice implements IExportableTransaction { return this; } + @Override + public String getVATDueDateTypeCode() { + return vatDueDateTypeCode; + } + + /** + * Decide when the VAT should be collected. + * @param vatDueDateTypeCode use EventTimeCodeTypeConstants + */ + public Invoice setVATDueDateTypeCode(String vatDueDateTypeCode) { + this.vatDueDateTypeCode = vatDueDateTypeCode; + return this; + } + } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java index c88ecfd8..fb8fa602 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java @@ -497,4 +497,8 @@ public interface IExportableTransaction { return null; } + default String getVATDueDateTypeCode() { + 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 282ced71..b67e7598 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java @@ -164,13 +164,14 @@ public class TransactionCalculator implements IAbsoluteValueProvider { */ protected HashMap getVATPercentAmountMap() { HashMap hm = new HashMap<>(); + final String vatDueDateTypeCode = trans.getVATDueDateTypeCode(); for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { BigDecimal percent = currentItem.getProduct().getVATPercent(); if (percent != null) { LineCalculator lc = new LineCalculator(currentItem); VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), - currentItem.getProduct().getTaxCategoryCode()); + currentItem.getProduct().getTaxCategoryCode(), vatDueDateTypeCode); VATAmount current = hm.get(percent.stripTrailingZeros()); if (current == null) { hm.put(percent.stripTrailingZeros(), itemVATAmount); @@ -188,7 +189,8 @@ public class TransactionCalculator implements IAbsoluteValueProvider { VATAmount theAmount = hm.get(taxPercent.stripTrailingZeros()); if (theAmount == null) { theAmount = new VATAmount(BigDecimal.ZERO, BigDecimal.ZERO, - currentCharge.getCategoryCode() != null ? currentCharge.getCategoryCode() : "S"); + currentCharge.getCategoryCode() != null ? currentCharge.getCategoryCode() : "S", + vatDueDateTypeCode); } theAmount.setBasis(theAmount.getBasis().add(currentCharge.getTotalAmount(this))); BigDecimal factor = taxPercent.divide(new BigDecimal(100)); @@ -205,7 +207,8 @@ public class TransactionCalculator implements IAbsoluteValueProvider { VATAmount theAmount = hm.get(taxPercent.stripTrailingZeros()); if (theAmount == null) { theAmount = new VATAmount(BigDecimal.ZERO, BigDecimal.ZERO, - currentAllowance.getCategoryCode() != null ? currentAllowance.getCategoryCode() : "S"); + currentAllowance.getCategoryCode() != null ? currentAllowance.getCategoryCode() : "S", + vatDueDateTypeCode); } theAmount.setBasis(theAmount.getBasis().subtract(currentAllowance.getTotalAmount(this))); BigDecimal factor = taxPercent.divide(new BigDecimal(100)); diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java b/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java index 6644d97e..a7a82f61 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java @@ -37,12 +37,23 @@ public class VATAmount { this.basis = basis; this.calculated = calculated; this.categoryCode = categoryCode; + this.dueDateTypeCode = null; + } + + public VATAmount(BigDecimal basis, BigDecimal calculated, String categoryCode, String dueDateTypeCode) { + super(); + this.basis = basis; + this.calculated = calculated; + this.categoryCode = categoryCode; + this.dueDateTypeCode = dueDateTypeCode; } BigDecimal basis, calculated, applicablePercent; String categoryCode; + String dueDateTypeCode; + public BigDecimal getApplicablePercent() { return applicablePercent; } @@ -95,12 +106,20 @@ public class VATAmount { this.categoryCode = categoryCode; } + public String getDueDateTypeCode() { + return dueDateTypeCode; + } + + public void setDueDateTypeCode(String dueDateTypeCode) { + this.dueDateTypeCode = dueDateTypeCode; + } + public VATAmount add(VATAmount v) { - return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode); + return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode, this.dueDateTypeCode); } public VATAmount subtract(VATAmount v) { - return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.categoryCode); + return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.categoryCode, this.dueDateTypeCode); } } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java index 7828849d..55423cee 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java @@ -271,6 +271,7 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr final VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); if (amount != null) { final String amountCategoryCode = amount.getCategoryCode(); + final String amountDueDateTypeCode = amount.getDueDateTypeCode(); final boolean displayExemptionReason = CATEGORY_CODES_WITH_EXEMPTION_REASON.contains(amountCategoryCode); xml += "" + "" + currencyFormat(amount.getCalculated()) @@ -279,6 +280,7 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr + (displayExemptionReason ? exemptionReason : "") + "" + currencyFormat(amount.getBasis()) + "" // currencyID=\"EUR\" + "" + amount.getCategoryCode() + "" + + (amountDueDateTypeCode != null ? "" + amountDueDateTypeCode + "" : "") + "" + vatFormat(currentTaxPercent) + ""; } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 53ce58db..7992ef08 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -618,6 +618,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { final VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); if (amount != null) { final String amountCategoryCode = amount.getCategoryCode(); + final String amountDueDateTypeCode = amount.getDueDateTypeCode(); final boolean displayExemptionReason = CATEGORY_CODES_WITH_EXEMPTION_REASON.contains(amountCategoryCode); if (getProfile() != Profiles.getByName("Minimum")) { @@ -628,6 +629,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { + (displayExemptionReason ? exemptionReason : "") + "" + currencyFormat(amount.getBasis()) + "" // currencyID=\"EUR\" + "" + amountCategoryCode + "" + + (amountDueDateTypeCode != null ? "" + amountDueDateTypeCode + "" : "") + "" + vatFormat(currentTaxPercent) + ""; } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/model/EventTimeCodeTypeConstants.java b/library/src/main/java/org/mustangproject/ZUGFeRD/model/EventTimeCodeTypeConstants.java new file mode 100644 index 00000000..6ebb54ce --- /dev/null +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/model/EventTimeCodeTypeConstants.java @@ -0,0 +1,25 @@ +/** ********************************************************************** + * + * 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; + +public class EventTimeCodeTypeConstants { + public static final String INVOICE_DATE = "5"; + public static final String DELIVERY_DATE = "29"; + public static final String PAYMENT_DATE = "72"; +} diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java index 3b73e989..d1292d06 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java @@ -33,6 +33,8 @@ import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; import junit.framework.TestCase; + +import org.mustangproject.ZUGFeRD.model.EventTimeCodeTypeConstants; import org.xmlunit.builder.Input; import org.xmlunit.xpath.JAXPXPathEngine; import org.xmlunit.xpath.XPathEngine; @@ -390,7 +392,7 @@ public class ZF2PushTest extends TestCase { .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(16)).addGlobalID(gtin), price, new BigDecimal(1.0)).addReferencedLineID("xxx").addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15"))) .addCharge(new Charge(new BigDecimal(0.5)).setReason("quick delivery charge").setTaxPercent(new BigDecimal(16))) .addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16))) - .setDeliveryDate(sdf.parse("2020-11-02")).setOwnVATID("DE0815").setNumber(number) + .setDeliveryDate(sdf.parse("2020-11-02")).setOwnVATID("DE0815").setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE) ); } catch (ParseException e) { e.printStackTrace(); @@ -429,6 +431,8 @@ public class ZF2PushTest extends TestCase { assertFalse(zi.getUTF8().contains("DE47110")); // but not the VAT ID of the shiptotradeparty assertTrue(zi.getUTF8().contains("document level 2/2")); assertFalse(zi.getUTF8().contains("++49555123456")); // in profile EN16931 contact fax number is not allowed + assertThat(zi.getUTF8()).valueByXPath("//*[local-name()='ApplicableTradeTax']/*[local-name()='DueDateTypeCode']").asString() + .isEqualTo(EventTimeCodeTypeConstants.PAYMENT_DATE); ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_PUSHEDGE); try {