Consider tax category code when writing exemption reason in ApplicableHeaderTradeSettlement

To prevent the following error:
<error type="4" location="/*[local-name()='CrossIndustryInvoice']/*[local-name()='SupplyChainTradeTransaction']/*[local-name()='ApplicableHeaderTradeSettlement']/*[local-name()='ApplicableTradeTax'][2]/*[local-name()='CategoryCode']" criterion="not(../ram:ExemptionReason) and not (../ram:ExemptionReasonCode)">A VAT Breakdown (BG-23) with VAT Category code (BT-118) "Standard rate" shall not have a VAT exemption reason code (BT-121) or VAT exemption reason text (BT-120).</error>
      <error type="24" location="/*:CrossIndustryInvoice[namespace-uri()='urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'][1]/*:SupplyChainTradeTransaction[namespace-uri()='urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'][1]/*:ApplicableHeaderTradeSettlement[namespace-uri()='urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'][1]/*:ApplicableTradeTax[namespace-uri()='urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'][2]/*:CategoryCode[namespace-uri()='urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'][1]" criterion="not(../ram:ExemptionReason) and not (../ram:ExemptionReasonCode)">[BR-S-10]-A VAT Breakdown (BG-23) with VAT Category code (BT-118) "Standard rate" shall not have a VAT exemption reason code (BT-121) or VAT exemption reason text (BT-120).</error>
This commit is contained in:
Sebastian Sieber
2021-02-15 14:09:07 +01:00
parent b69f3b6d67
commit 417e899cab
3 changed files with 25 additions and 14 deletions

View File

@@ -20,6 +20,8 @@
*/ */
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import static org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants.CATEGORY_CODES_WITH_EXEMPTION_REASON;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@@ -263,16 +265,17 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr
for (final BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { for (final BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
final VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); final VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
if (amount != null) { if (amount != null) {
final String amountCategoryCode = amount.getCategoryCode();
final boolean displayExemptionReason = CATEGORY_CODES_WITH_EXEMPTION_REASON.contains(amountCategoryCode);
xml += " <ram:ApplicableTradeTax>\n" xml += " <ram:ApplicableTradeTax>\n"
+ " <ram:CalculatedAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(amount.getCalculated()) + " <ram:CalculatedAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(amount.getCalculated())
+ "</ram:CalculatedAmount>\n" //currencyID=\"EUR\" + "</ram:CalculatedAmount>\n" //currencyID=\"EUR\"
+ " <ram:TypeCode>VAT</ram:TypeCode>\n" + " <ram:TypeCode>VAT</ram:TypeCode>\n"
+ exemptionReason + (displayExemptionReason ? exemptionReason : "")
+ " <ram:BasisAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>\n" // currencyID=\"EUR\" + " <ram:BasisAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>\n" // currencyID=\"EUR\"
+ " <ram:CategoryCode>" + amount.getCategoryCode() + "</ram:CategoryCode>\n" + " <ram:CategoryCode>" + amount.getCategoryCode() + "</ram:CategoryCode>\n"
+ " <ram:ApplicablePercent>" + vatFormat(currentTaxPercent) + " <ram:ApplicablePercent>" + vatFormat(currentTaxPercent)
+ "</ram:ApplicablePercent>\n" + " </ram:ApplicableTradeTax>\n"; + "</ram:ApplicablePercent>\n" + " </ram:ApplicableTradeTax>\n";
} }
} }

View File

@@ -21,6 +21,7 @@
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import static org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants.CORRECTEDINVOICE; import static org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants.CORRECTEDINVOICE;
import static org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants.CATEGORY_CODES_WITH_EXEMPTION_REASON;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
@@ -29,7 +30,7 @@ import java.math.BigDecimal;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Base64; import java.util.Base64;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -507,20 +508,21 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
hasDueDate = false; hasDueDate = false;
} }
final HashMap<BigDecimal, VATAmount> VATPercentAmountMap = calc.getVATPercentAmountMap(); final Map<BigDecimal, VATAmount> VATPercentAmountMap = calc.getVATPercentAmountMap();
for (final BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { for (final BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
final VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); final VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
if (amount != null) { if (amount != null) {
xml += " <ram:ApplicableTradeTax>\n" final String amountCategoryCode = amount.getCategoryCode();
+ " <ram:CalculatedAmount>" + currencyFormat(amount.getCalculated()) final boolean displayExemptionReason = CATEGORY_CODES_WITH_EXEMPTION_REASON.contains(amountCategoryCode);
+ "</ram:CalculatedAmount>\n" //currencyID=\"EUR\" xml += " <ram:ApplicableTradeTax>\n"
+ " <ram:TypeCode>VAT</ram:TypeCode>\n" + " <ram:CalculatedAmount>" + currencyFormat(amount.getCalculated())
+ exemptionReason + "</ram:CalculatedAmount>\n" //currencyID=\"EUR\"
+ " <ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>\n" // currencyID=\"EUR\" + " <ram:TypeCode>VAT</ram:TypeCode>\n"
+ " <ram:CategoryCode>" + amount.getCategoryCode() + "</ram:CategoryCode>\n" + (displayExemptionReason ? exemptionReason : "")
+ " <ram:RateApplicablePercent>" + vatFormat(currentTaxPercent) + " <ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>\n" // currencyID=\"EUR\"
+ "</ram:RateApplicablePercent>\n" + " </ram:ApplicableTradeTax>\n"; + " <ram:CategoryCode>" + amountCategoryCode + "</ram:CategoryCode>\n"
+ " <ram:RateApplicablePercent>"
+ vatFormat(currentTaxPercent) + "</ram:RateApplicablePercent>\n" + " </ram:ApplicableTradeTax>\n" ;
} }
} }
if ((trans.getDetailedDeliveryPeriodFrom() != null) || (trans.getDetailedDeliveryPeriodTo() != null)) { if ((trans.getDetailedDeliveryPeriodFrom() != null) || (trans.getDetailedDeliveryPeriodTo() != null)) {

View File

@@ -18,6 +18,10 @@
*********************************************************************** */ *********************************************************************** */
package org.mustangproject.ZUGFeRD.model; package org.mustangproject.ZUGFeRD.model;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TaxCategoryCodeTypeConstants { public class TaxCategoryCodeTypeConstants {
public static final String STANDARDRATE = "S"; public static final String STANDARDRATE = "S";
public static final String REVERSECHARGE = "AE"; public static final String REVERSECHARGE = "AE";
@@ -25,4 +29,6 @@ public class TaxCategoryCodeTypeConstants {
public static final String ZEROTAXPRODUCTS = "Z"; public static final String ZEROTAXPRODUCTS = "Z";
public static final String UNTAXEDSERVICE = "O"; public static final String UNTAXEDSERVICE = "O";
public static final String INTRACOMMUNITY = "K"; public static final String INTRACOMMUNITY = "K";
public static Set<String> CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE).collect(Collectors.toSet());
} }