Merge pull request #309 from chris-webert-its4u/issues/308-vat-due-date
Issue 308: define when VAT collection become applicable
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -497,4 +497,8 @@ public interface IExportableTransaction {
|
||||
return null;
|
||||
}
|
||||
|
||||
default String getVATDueDateTypeCode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -164,13 +164,14 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
||||
*/
|
||||
protected HashMap<BigDecimal, VATAmount> getVATPercentAmountMap() {
|
||||
HashMap<BigDecimal, VATAmount> 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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 += "<ram:ApplicableTradeTax>"
|
||||
+ "<ram:CalculatedAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(amount.getCalculated())
|
||||
@@ -279,6 +280,7 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr
|
||||
+ (displayExemptionReason ? exemptionReason : "")
|
||||
+ "<ram:BasisAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>" // currencyID=\"EUR\"
|
||||
+ "<ram:CategoryCode>" + amount.getCategoryCode() + "</ram:CategoryCode>"
|
||||
+ (amountDueDateTypeCode != null ? "<ram:DueDateTypeCode>" + amountDueDateTypeCode + "</ram:DueDateTypeCode>" : "")
|
||||
+ "<ram:ApplicablePercent>" + vatFormat(currentTaxPercent)
|
||||
+ "</ram:ApplicablePercent></ram:ApplicableTradeTax>";
|
||||
}
|
||||
|
||||
@@ -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 : "")
|
||||
+ "<ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>" // currencyID=\"EUR\"
|
||||
+ "<ram:CategoryCode>" + amountCategoryCode + "</ram:CategoryCode>"
|
||||
+ (amountDueDateTypeCode != null ? "<ram:DueDateTypeCode>" + amountDueDateTypeCode + "</ram:DueDateTypeCode>" : "")
|
||||
+ "<ram:RateApplicablePercent>"
|
||||
+ vatFormat(currentTaxPercent) + "</ram:RateApplicablePercent></ram:ApplicableTradeTax>";
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user