first step to support tax category codes

This commit is contained in:
Jochen Stärk
2019-10-13 18:16:54 +02:00
parent c906bf8f64
commit 293134af63
5 changed files with 305 additions and 256 deletions

View File

@@ -1,8 +1,9 @@
1. 1.7.5
===== =====
2019- 2019-10-
- support Sepa Direct Debit - support Sepa Direct Debit
- closes #134 ZUGFeRD2PullProvider uses NetPrice for GrossPrice
1.7.4 1.7.4
===== =====

View File

@@ -81,5 +81,10 @@ public interface IZUGFeRDExportableProduct {
* @return VAT percent of the product * @return VAT percent of the product
*/ */
BigDecimal getVATPercent(); BigDecimal getVATPercent();
default String getTaxCategoryCode() {
return "S";
}
} }

View File

@@ -319,7 +319,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
+ " <ram:SpecifiedLineTradeSettlement>\n" //$NON-NLS-1$ + " <ram:SpecifiedLineTradeSettlement>\n" //$NON-NLS-1$
+ " <ram:ApplicableTradeTax>\n" //$NON-NLS-1$ + " <ram:ApplicableTradeTax>\n" //$NON-NLS-1$
+ " <ram:TypeCode>VAT</ram:TypeCode>\n" //$NON-NLS-1$ + " <ram:TypeCode>VAT</ram:TypeCode>\n" //$NON-NLS-1$
+ " <ram:CategoryCode>S</ram:CategoryCode>\n" //$NON-NLS-1$ + " <ram:CategoryCode>"+currentItem.getProduct().getTaxCategoryCode()+"</ram:CategoryCode>\n" //$NON-NLS-1$
+ " <ram:RateApplicablePercent>" //$NON-NLS-1$ + " <ram:RateApplicablePercent>" //$NON-NLS-1$
+ vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>\n" //$NON-NLS-1$ + vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>\n" //$NON-NLS-1$
+ " </ram:ApplicableTradeTax>\n" //$NON-NLS-1$ + " </ram:ApplicableTradeTax>\n" //$NON-NLS-1$

View File

@@ -125,7 +125,7 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
protected class Item implements IZUGFeRDExportableItem { protected class Item implements IZUGFeRDExportableItem {
public Item(BigDecimal price, BigDecimal quantity, Product product) { public Item(BigDecimal price, BigDecimal quantity, IZUGFeRDExportableProduct product) {
super(); super();
this.price = price; this.price = price;
this.quantity = quantity; this.quantity = quantity;
@@ -133,7 +133,7 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
} }
private BigDecimal price, quantity; private BigDecimal price, quantity;
private Product product; private IZUGFeRDExportableProduct product;
@Override @Override
public BigDecimal getPrice() { public BigDecimal getPrice() {
@@ -154,11 +154,11 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
} }
@Override @Override
public Product getProduct() { public IZUGFeRDExportableProduct getProduct() {
return product; return product;
} }
public void setProduct(Product product) { public void setProduct(IZUGFeRDExportableProduct product) {
this.product = product; this.product = product;
} }

View File

@@ -1,279 +1,322 @@
/** ********************************************************************** /** **********************************************************************
* *
* Copyright 2019 Jochen Staerk * Copyright 2019 Jochen Staerk
* *
* Use is subject to license terms. * Use is subject to license terms.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * 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. * of the License at http://www.apache.org/licenses/LICENSE-2.0.
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* *
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* *
*********************************************************************** */ *********************************************************************** */
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ZF2EdgeTest extends MustangReaderTestCase {
final String TARGET_PDF = "./target/testout-ZF2newEdge.pdf";
import junit.framework.Test;
import junit.framework.TestSuite;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ZF2EdgeTest extends MustangReaderTestCase implements IZUGFeRDExportableTransaction {
final String TARGET_PDF = "./target/testout-ZF2newEdge.pdf";
protected class EdgeProduct implements IZUGFeRDExportableProduct {
private String description, name, unit;
public EdgeProduct(String description, String name, String unit) {
super();
this.description = description;
this.name = name;
this.unit = unit;
}
@Override
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
@Override
public BigDecimal getVATPercent() {
return BigDecimal.ZERO;
}
@Override
public String getTaxCategoryCode() {
return "K"; // simulate intra community supply
}
}
protected class DebitPayment implements IZUGFeRDTradeSettlementDebit { protected class DebitPayment implements IZUGFeRDTradeSettlementDebit {
@Override @Override
public String getIBAN() { public String getIBAN() {
return "DE540815"; return "DE540815";
} }
@Override @Override
public String getMandate() { public String getMandate() {
return "DE99XX12345"; return "DE99XX12345";
} }
} }
@Override @Override
public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() { public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
return null; return null;
} }
@Override @Override
public IZUGFeRDTradeSettlement[] getTradeSettlement() { public IZUGFeRDTradeSettlement[] getTradeSettlement() {
IZUGFeRDTradeSettlement[] payments = new DebitPayment[1]; IZUGFeRDTradeSettlement[] payments = new DebitPayment[1];
payments[0] = new DebitPayment(); payments[0] = new DebitPayment();
return payments; return payments;
} }
@Override
@Override public Date getDeliveryDate() {
public Date getDeliveryDate() { return new GregorianCalendar(2017, Calendar.MAY, 7).getTime();
return new GregorianCalendar(2017, Calendar.MAY, 7).getTime(); }
}
@Override
@Override public Date getDueDate() {
public Date getDueDate() { return new GregorianCalendar(2017, Calendar.MAY, 30).getTime();
return new GregorianCalendar(2017, Calendar.MAY, 30).getTime(); }
}
@Override
@Override public Date getIssueDate() {
public Date getIssueDate() { return new GregorianCalendar(2017, Calendar.MAY, 9).getTime();
return new GregorianCalendar(2017, Calendar.MAY, 9).getTime(); }
}
@Override
@Override public String getNumber() {
public String getNumber() { return "RE-20170509/505";
return "RE-20170509/505"; }
}
@Override
@Override public String getOwnCountry() {
public String getOwnCountry() { return "DE";
return "DE"; }
}
@Override
@Override public String getOwnLocation() {
public String getOwnLocation() { return "Stadthausen";
return "Stadthausen"; }
}
@Override
@Override public String getOwnOrganisationName() {
public String getOwnOrganisationName() { return "Bei Spiel GmbH";
return "Bei Spiel GmbH"; }
}
@Override
@Override public String getOwnStreet() {
public String getOwnStreet() { return "Ecke 12";
return "Ecke 12"; }
}
@Override
@Override public IZUGFeRDExportableContact getOwnContact() {
public IZUGFeRDExportableContact getOwnContact() { return new SenderContact();
return new SenderContact();
}
}
@Override
@Override public String getOwnTaxID() {
public String getOwnTaxID() { return "22/815/0815/4";
return "22/815/0815/4"; }
}
@Override
@Override public String getOwnVATID() {
public String getOwnVATID() { return "DE136695976";
return "DE136695976"; }
}
@Override
@Override public String getOwnZIP() {
public String getOwnZIP() { return "12345";
return "12345"; }
}
@Override
@Override public IZUGFeRDExportableContact getRecipient() {
public IZUGFeRDExportableContact getRecipient() { return new RecipientContact();
return new RecipientContact(); }
}
@Override
@Override public String getOwnOrganisationFullPlaintextInfo() {
public String getOwnOrganisationFullPlaintextInfo() { return null;
return null; }
}
@Override
@Override public String getCurrency() {
public String getCurrency() { return "EUR";
return "EUR"; }
}
@Override
@Override public IZUGFeRDExportableItem[] getZFItems() {
public IZUGFeRDExportableItem[] getZFItems() { Item[] allItems = new Item[2];
Item[] allItems = new Item[3]; EdgeProduct designProduct = new EdgeProduct("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung",
Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR", "HUR");
new BigDecimal("7.000000")); EdgeProduct balloonProduct = new EdgeProduct("", "Bestellerweiterung für E&F Umbau", "C62");// test for issue
Product balloonProduct = new Product("", "Bestellerweiterung für E&F Umbau", "C62", // 103
new BigDecimal("19.000000"));// test for issue 103 EdgeProduct airProduct = new EdgeProduct("", "Heiße Luft pro Liter", "LTR");
Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000"));
allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct); allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct);
allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct); allItems[2] = new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct);
allItems[2] = new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct); return allItems;
return allItems; }
}
@Override
@Override public String getPaymentTermDescription() {
public String getPaymentTermDescription() { SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); return "Zahlbar ohne Abzug bis zum " + germanDateFormat.format(getDueDate());
return "Zahlbar ohne Abzug bis zum " + germanDateFormat.format(getDueDate()); }
}
@Override
@Override public IZUGFeRDAllowanceCharge[] getZFAllowances() {
public IZUGFeRDAllowanceCharge[] getZFAllowances() { return null;
return null; }
}
@Override
@Override public IZUGFeRDAllowanceCharge[] getZFCharges() {
public IZUGFeRDAllowanceCharge[] getZFCharges() { return null;
return null; }
}
@Override
@Override public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() { return null;
return null; }
}
@Override
@Override public String getReferenceNumber() {
public String getReferenceNumber() { return "AB321";
return "AB321"; }
}
/**
/** * Create the test case
* Create the test case *
* * @param testName name of the test case
* @param testName name of the test case */
*/ public ZF2EdgeTest(String testName) {
public ZF2EdgeTest(String testName) { super(testName);
super(testName); }
}
/**
/** * @return the suite of tests being tested
* @return the suite of tests being tested */
*/ public static Test suite() {
public static Test suite() { return new TestSuite(ZF2EdgeTest.class);
return new TestSuite(ZF2EdgeTest.class); }
}
// //////// TESTS
// //////// TESTS // //////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////
/**
/** * The exporter test bases on @{code
* The exporter test bases on @{code * ./src/test/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf}, adds
* ./src/test/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf}, adds * metadata, writes to @{code ./target/testout-*} and then imports to check the
* metadata, writes to @{code ./target/testout-*} and then imports to check the * values.
* values. */
*/ public void testEdgeExport() {
public void testEdgeExport() {
// the writing part
// the writing part
try (InputStream SOURCE_PDF = this.getClass()
try (InputStream SOURCE_PDF = this.getClass() .getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application")
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application") .setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors() .load(SOURCE_PDF)) {
.load(SOURCE_PDF)) { ze.PDFattachZugferdFile(this);
ze.PDFattachZugferdFile(this); String theXML = new String(ze.getProvider().getXML());
String theXML = new String(ze.getProvider().getXML()); assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice")); ze.export(TARGET_PDF);
ze.export(TARGET_PDF); } catch (IOException e) {
} catch (IOException e) { fail("IOException should not be raised in testEdgeExport");
fail("IOException should not be raised in testEdgeExport"); }
}
// now check the contents (like MustangReaderTest)
// now check the contents (like MustangReaderTest) ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
assertTrue(zi.getUTF8().contains("<ram:TypeCode>59</ram:TypeCode>")); assertTrue(zi.getUTF8().contains("<ram:TypeCode>59</ram:TypeCode>"));
assertTrue(zi.getUTF8().contains("<ram:IBANID>DE540815</ram:IBANID>")); assertTrue(zi.getUTF8().contains("<ram:IBANID>DE540815</ram:IBANID>"));
assertTrue(zi.getUTF8().contains("<ram:DirectDebitMandateID>DE99XX12345</ram:DirectDebitMandateID>")); assertTrue(zi.getUTF8().contains("<ram:DirectDebitMandateID>DE99XX12345</ram:DirectDebitMandateID>"));
assertFalse(zi.getUTF8().contains("<ram:DueDateDateTime>")); assertFalse(zi.getUTF8().contains("<ram:DueDateDateTime>"));
// Reading ZUGFeRD // Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04"); assertEquals("496.00", zi.getAmount());
assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber()); assertEquals(zi.getForeignReference(), getNumber());
try { try {
assertEquals(zi.getVersion(), 2); assertEquals(zi.getVersion(), 2);
} catch (Exception e) { } catch (Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
} }
/** /**
* The exporter test bases on @{code * The exporter test bases on @{code
* ./src/test/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf}, adds * ./src/test/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf}, adds
* metadata, writes to @{code ./target/testout-*} and then imports to check the * metadata, writes to @{code ./target/testout-*} and then imports to check the
* values. * values.
*/ */
public void testOutputStreamExport() { public void testOutputStreamExport() {
// the writing part // the writing part
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (InputStream SOURCE_PDF = this.getClass() try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf"); .getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application") ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors() .setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) { .load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this); ze.PDFattachZugferdFile(this);
String theXML = new String(ze.getProvider().getXML()); String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice")); assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(bos); ze.export(bos);
} catch (IOException e) { } catch (IOException e) {
fail("IOException should not be raised in testEdgeExport"); fail("IOException should not be raised in testEdgeExport");
} }
} }
} }