Merge remote-tracking branch 'remotes/origin/master' into master

This commit is contained in:
Sebastian Sieber
2020-11-23 08:17:17 +01:00
17 changed files with 234 additions and 96 deletions

View File

@@ -1,19 +1,21 @@
### 2.0.1 todo
- 2.1 support kleinunternehmer, reverse charge?
- dont show empty tax number field
- fail when no bankverbindung?
- fail when xr attrs missing?
- build xr skonto???
- *validator not to XR error on ZF files (only notices)
- xmp errors may not show correctly in log
### 2.0.1 done
2.0.1
=====
2020-11-21
- corrected VAT calculation on prices with >2 decimals (PR#195 thanks to weclapp-dev)
- have fax numbers only in appropriate profiles, i.e., extended
- do not list tax numbers for shiptotradeparties
- do not expect dueDate for corrected invoices
- XR test now includes guideline ID #172
- XR test now includes guideline ID (of XRechnung 1.2.2) #172
- BigDecimal specific refactoring PR #192 Thanks to weclapp-dev
- Preserving metadata PR #193 Thanks to mr-stephan
- support zero-rated goods: confirm that VAT category code switches from S to Z on 0%VAT
- new sample invoice
- delivery period also on item level
- corrected more than 100 javadoc entries
- support specification of account (holder) names
- new sample invoice (20201121_508)
2.0.0
=====

View File

@@ -3,14 +3,14 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.0.0-alpha4-SNAPSHOT</version>
<version>2.0.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>Mustang-CLI</artifactId>
<name>Mustang commandline tool</name>
<packaging>jar</packaging>
<version>2.0.0-alpha4-SNAPSHOT</version>
<version>2.0.2-SNAPSHOT</version>
<repositories>
<repository>
<!-- for jargs -->
@@ -31,7 +31,7 @@
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>validator</artifactId>
<version>2.0.0-alpha4-SNAPSHOT</version>
<version>2.0.2-SNAPSHOT</version>
<!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with
mvn install:install-file -Dfile=mustang-1.5.4-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.5.4 -Dpackaging=jar -DgeneratePom=true
-->

View File

@@ -3,13 +3,13 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.0.0-alpha4-SNAPSHOT</version>
<version>2.0.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.0.0-alpha4-SNAPSHOT</version>
<version>2.0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Library to write and read FacturX and ZUGFeRD e-invoices. </name>
<description>The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs. To write files, a provided PDF/A will be combined with generated or provided XML.

View File

@@ -6,7 +6,7 @@ import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlementPayment;
* provides e.g. the IBAN to transfer money to :-)
*/
public class BankDetails implements IZUGFeRDTradeSettlementPayment {
protected String IBAN, BIC;
protected String IBAN, BIC, accountName=null;
public BankDetails(String IBAN, String BIC) {
this.IBAN = IBAN;
@@ -34,6 +34,11 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
return BIC;
}
/***
* The bank identifier. Bank name is no longer neccessary in SEPA.
* @param BIC the bic code
* @return fluent setter
*/
public BankDetails setBIC(String BIC) {
this.BIC = BIC;
return this;
@@ -55,6 +60,21 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
}
/**
* set Holder
* @param name account name (usually account holder if != sender)
* @return fluent setter
*/
public BankDetails setAccountName(String name) {
accountName=name;
return this;
}
@Override
public String getAccountName() {
return accountName;
}
}

View File

@@ -5,12 +5,14 @@ import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
/***
* describes any invoice line
*/
public class Item implements IZUGFeRDExportableItem {
protected BigDecimal price, quantity, tax, grossPrice, lineTotalAmount;
protected Date detailedDeliveryPeriodFrom=null, detailedDeliveryPeriodTo=null;
protected String id;
protected Product product;
protected ArrayList<String> notes = null;
@@ -58,6 +60,7 @@ public class Item implements IZUGFeRDExportableItem {
return this;
}
public BigDecimal getTax() {
return tax;
}
@@ -135,11 +138,23 @@ public class Item implements IZUGFeRDExportableItem {
}
/***
* Adds a item level addition to the price (will be multiplied by quantity)
* @see org.mustangproject.Charge
* @param izac a relative or absolute charge
* @return fluent setter
*/
public Item addCharge(IZUGFeRDAllowanceCharge izac) {
Charges.add(izac);
return this;
}
/***
* Adds a item level reduction the price (will be multiplied by quantity)
* @see org.mustangproject.Allowance
* @param izac a relative or absolute allowance
* @return fluent setter
*/
public Item addAllowance(IZUGFeRDAllowanceCharge izac) {
Allowances.add(izac);
return this;
@@ -158,5 +173,37 @@ public class Item implements IZUGFeRDExportableItem {
return this;
}
/***
* specify a item level delivery period
* (apart from the document level delivery period, and the document level
* delivery day, which is probably anyway required)
*
* @param from start date
* @param to end date
* @return fluent setter
*/
public Item setDetailedDeliveryPeriod(Date from, Date to) {
detailedDeliveryPeriodFrom=from;
detailedDeliveryPeriodTo=to;
return this;
}
/***
* specifies the item level delivery period (there is also one on document level),
* this will be included in a BillingSpecifiedPeriod element
* @return the beginning of the delivery period
*/
public Date getDetailedDeliveryPeriodFrom() {
return detailedDeliveryPeriodFrom;
}
/***
* specifies the item level delivery period (there is also one on document level),
* this will be included in a BillingSpecifiedPeriod element
* @return the end of the delivery period
*/
public Date getDetailedDeliveryPeriodTo() {
return detailedDeliveryPeriodTo;
}
}

View File

@@ -27,6 +27,7 @@ package org.mustangproject.ZUGFeRD;
* */
import java.math.BigDecimal;
import java.util.Date;
public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
@@ -88,4 +89,24 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
return null;
}
/***
* specifies the item level delivery period (there is also one on document level),
* this will be included in a BillingSpecifiedPeriod element
* @return the beginning of the delivery period
*/
default Date getDetailedDeliveryPeriodFrom() {
return null;
}
/***
* specifies the item level delivery period (there is also one on document level),
* this will be included in a BillingSpecifiedPeriod element
* @return the end of the delivery period
*/
default Date getDetailedDeliveryPeriodTo() {
return null;
}
}

View File

@@ -1,21 +1,23 @@
/** **********************************************************************
*
/**
* *********************************************************************
* <p>
* Copyright 2018 Jochen Staerk
*
* <p>
* Use is subject to license terms.
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
* <p>
* **********************************************************************
*/
package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
@@ -78,7 +80,7 @@ public interface IZUGFeRDExportableProduct {
/**
* Get the ID that had been assigned by the seller to
* identify the product
*
*
* @return seller assigned product ID
*/
default String getSellerAssignedID() {
@@ -88,33 +90,34 @@ public interface IZUGFeRDExportableProduct {
/**
* Get the ID that had been assigned by the buyer to
* identify the product
*
*
* @return buyer assigned product ID
*/
default String getBuyerAssignedID() {
return null;
}
/**
* VAT percent of the product (e.g. 19, or 5.1 if you like)
*
* @return VAT percent of the product
*/
BigDecimal getVATPercent();
default boolean isIntraCommunitySupply() {
return false;
}
default String getTaxCategoryCode() {
if (getVATPercent().equals(new BigDecimal(0))) {
if (isIntraCommunitySupply()) {
return "K";
} else if (getVATPercent().equals(new BigDecimal(0))) {
return "Z"; // zero rated goods
} else if (isIntraCommunitySupply()) {
return "K";
} else {
return "S"; // one of the "standard" rates (not neccessarily a default rate, even a deducted VAT is standard calculation)
}
}
} else {
return "S"; // one of the "standard" rates (not neccessarily a default rate, even a deducted VAT is standard calculation)
}
}
default String getTaxExemptionReason() {
if (isIntraCommunitySupply())
return "Intra-community supply";

View File

@@ -52,14 +52,28 @@ public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement
return null;
}
/***
* Account name
*
* @return the name of the account holder (if not identical to sender)
*/
default String getAccountName() { return null; }
default String getSettlementXML() {
String accountNameStr="";
if (getAccountName()!=null) {
accountNameStr="<ram:AccountName>" + XMLTools.encodeXML(getAccountName()) + "</ram:AccountName>\n"; //$NON-NLS-2$
}
String xml = " <ram:SpecifiedTradeSettlementPaymentMeans>\n"
+ " <ram:TypeCode>42</ram:TypeCode>\n"
+ " <ram:Information>Überweisung</ram:Information>\n"
+ " <ram:Information>Bank transfer</ram:Information>\n"
+ " <ram:PayeePartyCreditorFinancialAccount>\n"
+ " <ram:IBANID>" + XMLTools.encodeXML(getOwnIBAN()) + "</ram:IBANID>\n"; //$NON-NLS-2$
xml+= " </ram:PayeePartyCreditorFinancialAccount>\n"
xml+= accountNameStr;
xml+= " </ram:PayeePartyCreditorFinancialAccount>\n"
+ " <ram:PayeeSpecifiedCreditorFinancialInstitution>\n"
+ " <ram:BICID>" + XMLTools.encodeXML(getOwnBIC()) + "</ram:BICID>\n" //$NON-NLS-2$
// + " <ram:Name>"+trans.getOwnBankName()+"</ram:Name>\n"

View File

@@ -33,7 +33,7 @@ public class Profiles {
{"BASIC", new Profile("BASIC", "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic")},
{"EN16931", new Profile("EN16931", "urn:cen.eu:en16931:2017")},
{"EXTENDED", new Profile("EXTENDED", "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended")},
{"XRECHNUNG", new Profile("XRECHNUNG", "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0")}
{"XRECHNUNG", new Profile("XRECHNUNG", "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_1.2")}
}).collect(Collectors.toMap(data -> (String) data[0], data -> (Profile) data[1]));
static Map<String, Profile> zf1Map = Stream.of(new Object[][]{

View File

@@ -107,6 +107,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
// @todo check if the two boolean args can be refactored
/***
* returns the UN/CEFACT CII XML for companies(tradeparties), which is actually
* the same for ZF1 (v 2013b) and ZF2 (v 2016b)
@@ -127,7 +128,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
xml += " <ram:Name>" + XMLTools.encodeXML(party.getName()) + "</ram:Name>\n"; //$NON-NLS-2$
if ((party.getContact() != null)&&(isSender||profile==Profiles.getByName("Extended"))) {
if ((party.getContact() != null) && (isSender || profile == Profiles.getByName("Extended"))) {
xml = xml + "<ram:DefinedTradeContact>\n" + " <ram:PersonName>" + XMLTools.encodeXML(party.getContact().getName())
+ "</ram:PersonName>\n";
if (party.getContact().getPhone() != null) {
@@ -137,8 +138,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ " </ram:TelephoneUniversalCommunication>\n";
}
if (party.getContact().getFax() != null) {
if ((party.getContact().getFax() != null) && (profile == Profiles.getByName("Extended"))) {
xml = xml + " <ram:FaxUniversalCommunication>\n" + " <ram:CompleteNumber>"
+ XMLTools.encodeXML(party.getContact().getFax()) + "</ram:CompleteNumber>\n"
+ " </ram:FaxUniversalCommunication>\n";
@@ -167,13 +167,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ " <ram:CountryID>" + XMLTools.encodeXML(party.getCountry())
+ "</ram:CountryID>\n"
+ " </ram:PostalTradeAddress>\n";
if ((party.getVATID() != null)&&(!isShipToTradeParty)) {
if ((party.getVATID() != null) && (!isShipToTradeParty)) {
xml += " <ram:SpecifiedTaxRegistration>\n"
+ " <ram:ID schemeID=\"VA\">" + XMLTools.encodeXML(party.getVATID())
+ "</ram:ID>\n"
+ " </ram:SpecifiedTaxRegistration>\n";
}
if ((party.getTaxID() != null)&&(!isShipToTradeParty)) {
if ((party.getTaxID() != null) && (!isShipToTradeParty)) {
xml += " <ram:SpecifiedTaxRegistration>\n"
+ " <ram:ID schemeID=\"FC\">" + XMLTools.encodeXML(party.getTaxID())
+ "</ram:ID>\n"
@@ -194,7 +194,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
protected String getAllowanceChargeStr(IZUGFeRDAllowanceCharge allowance, IAbsoluteValueProvider item) {
String percentage = "";
String chargeIndicator = "false";
if ((allowance.getPercent() != null)&&(profile==Profiles.getByName("Extended"))) {
if ((allowance.getPercent() != null) && (profile == Profiles.getByName("Extended"))) {
percentage = "<ram:CalculationPercent>" + vatFormat(allowance.getPercent()) + "</ram:CalculationPercent>";
percentage += "<ram:BasisAmount>" + item.getValue() + "</ram:BasisAmount>";
}
@@ -202,15 +202,15 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
chargeIndicator = "true";
}
String reason="";
if ((allowance.getReason()!=null)&&(profile==Profiles.getByName("Extended"))) {
String reason = "";
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended"))) {
// only in extended profile
reason="<ram:Reason>"+XMLTools.encodeXML(allowance.getReason())+"</ram:Reason>";
reason = "<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>";
}
String allowanceChargeStr = "<ram:AppliedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" +
chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage +
"<ram:ActualAmount>" + priceFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount>" +
reason+
reason +
"</ram:AppliedTradeAllowanceCharge>";
return allowanceChargeStr;
}
@@ -229,7 +229,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
paymentTermsDescription = trans.getPaymentTermDescription();
}
if ((paymentTermsDescription == null)&&(trans.getDocumentCode()!= org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants.CORRECTEDINVOICE)) {
if ((paymentTermsDescription == null) && (trans.getDocumentCode() != org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants.CORRECTEDINVOICE)) {
paymentTermsDescription = "Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate());
}
@@ -379,8 +379,20 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ " <ram:RateApplicablePercent>"
+ vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>\n"
+ " </ram:ApplicableTradeTax>\n"
+ " <ram:SpecifiedTradeSettlementLineMonetarySummation>\n"
+ " </ram:ApplicableTradeTax>\n";
if ((currentItem.getDetailedDeliveryPeriodFrom() != null) || (currentItem.getDetailedDeliveryPeriodTo() != null)) {
xml = xml + "<ram:BillingSpecifiedPeriod>";
if (currentItem.getDetailedDeliveryPeriodFrom() != null) {
xml = xml + "<ram:StartDateTime><udt:DateTimeString format='102'>" + zugferdDateFormat.format(currentItem.getDetailedDeliveryPeriodFrom()) + "</udt:DateTimeString></ram:StartDateTime>";
}
if (currentItem.getDetailedDeliveryPeriodTo() != null) {
xml = xml + "<ram:EndDateTime><udt:DateTimeString format='102'>" + zugferdDateFormat.format(currentItem.getDetailedDeliveryPeriodTo()) + "</udt:DateTimeString></ram:EndDateTime>";
}
xml = xml + "</ram:BillingSpecifiedPeriod>";
}
xml = xml + " <ram:SpecifiedTradeSettlementLineMonetarySummation>\n"
+ " <ram:LineTotalAmount>" + currencyFormat(lc.getItemTotalNetAmount())
+ "</ram:LineTotalAmount>\n" // currencyID=\"EUR\"
+ " </ram:SpecifiedTradeSettlementLineMonetarySummation>\n";
@@ -430,7 +442,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ " <ram:TypeCode>916</ram:TypeCode>\n"
+ " <ram:Name>" + f.getDescription() + "</ram:Name>\n"
+ " <ram:AttachmentBinaryObject mimeCode=\"" + f.getMimetype() + "\"\n"
+ " filename=\"" + f.getFilename() + ">" + documentContent + "\n"
+ " filename=\"" + f.getFilename() + "\">" + documentContent + "\n"
+ " </ram:AdditionalReferencedDocument>\n";
}
}
@@ -482,8 +494,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
}
}
if (trans.getDocumentCode()== DocumentCodeTypeConstants.CORRECTEDINVOICE) {
hasDueDate=false;
if (trans.getDocumentCode() == DocumentCodeTypeConstants.CORRECTEDINVOICE) {
hasDueDate = false;
}
HashMap<BigDecimal, VATAmount> VATPercentAmountMap = calc.getVATPercentAmountMap();
@@ -518,7 +530,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if ((trans.getZFCharges() != null) && (trans.getZFCharges().length > 0)) {
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
if (calc.getChargesForPercent(currentTaxPercent).compareTo(BigDecimal.ZERO)!=0) {
if (calc.getChargesForPercent(currentTaxPercent).compareTo(BigDecimal.ZERO) != 0) {
xml = xml + " <ram:SpecifiedTradeAllowanceCharge>\n" +
@@ -526,7 +538,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
" <udt:Indicator>true</udt:Indicator>\n" +
" </ram:ChargeIndicator>\n" +
" <ram:ActualAmount>" + currencyFormat(calc.getChargesForPercent(currentTaxPercent)) + "</ram:ActualAmount>\n" +
" <ram:Reason>"+XMLTools.encodeXML(calc.getChargeReasonForPercent(currentTaxPercent))+"</ram:Reason>\n" +
" <ram:Reason>" + XMLTools.encodeXML(calc.getChargeReasonForPercent(currentTaxPercent)) + "</ram:Reason>\n" +
" <ram:CategoryTradeTax>\n" +
" <ram:TypeCode>VAT</ram:TypeCode>\n" +
" <ram:CategoryCode>" + VATPercentAmountMap.get(currentTaxPercent).getCategoryCode() + "</ram:CategoryCode>\n" +
@@ -541,13 +553,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if ((trans.getZFAllowances() != null) && (trans.getZFAllowances().length > 0)) {
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
if (calc.getAllowancesForPercent(currentTaxPercent).compareTo(BigDecimal.ZERO)!= 0) {
if (calc.getAllowancesForPercent(currentTaxPercent).compareTo(BigDecimal.ZERO) != 0) {
xml = xml + " <ram:SpecifiedTradeAllowanceCharge>\n" +
" <ram:ChargeIndicator>\n" +
" <udt:Indicator>false</udt:Indicator>\n" +
" </ram:ChargeIndicator>\n" +
" <ram:ActualAmount>" + currencyFormat(calc.getAllowancesForPercent(currentTaxPercent)) + "</ram:ActualAmount>\n" +
" <ram:Reason>"+XMLTools.encodeXML(calc.getAllowanceReasonForPercent(currentTaxPercent))+"</ram:Reason>\n" +
" <ram:Reason>" + XMLTools.encodeXML(calc.getAllowanceReasonForPercent(currentTaxPercent)) + "</ram:Reason>\n" +
" <ram:CategoryTradeTax>\n" +
" <ram:TypeCode>VAT</ram:TypeCode>\n" +
" <ram:CategoryCode>" + VATPercentAmountMap.get(currentTaxPercent).getCategoryCode() + "</ram:CategoryCode>\n" +
@@ -621,7 +633,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
try {
zugferdRaw = xml.getBytes("UTF-8");
zugferdData=XMLTools.removeBOM(zugferdRaw);
zugferdData = XMLTools.removeBOM(zugferdRaw);
} catch (UnsupportedEncodingException e) {
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e);
}

View File

@@ -141,6 +141,11 @@ public abstract class MustangReaderTestCase extends TestCase implements IExporta
return "0815";
}
@Override
public String getVATID() {
return "DE0815";
}
}
protected class Item implements IZUGFeRDExportableItem {

View File

@@ -37,7 +37,7 @@ import junit.framework.TestCase;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ZF2PushTest extends TestCase {
final String TARGET_PDF = "./target/testout-ZF2Push.pdf";
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20201121_508.pdf";
final String TARGET_ALLOWANCESPDF = "./target/testout-ZF2PushAllowances.pdf";
final String TARGET_CORRECTIONPDF = "./target/testout-ZF2PushCorrection.pdf";
final String TARGET_ITEMCHARGESALLOWANCESPDF = "./target/testout-ZF2PushItemChargesAllowances.pdf";
@@ -50,46 +50,48 @@ public class ZF2PushTest extends TestCase {
// the writing part
String orgname = "Test company";
String number = "RE-20170509/505";
String priceStr = "1.00";
String orgname = "Bei Spiel GmbH";
String number = "RE-20201121/508";
String priceStr = "160.00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
BigDecimal price = new BigDecimal(priceStr);
String occurenceFrom = "20201001";
String occurenceTo = "20201005";
String contractID = "376zreurzu0983";
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20201121_508blanko.pdf");
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) {
try {
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setContractReferencedDocument(contractID).setDetailedDeliveryPeriod(new SimpleDateFormat("yyyyMMdd").parse(occurenceFrom), new SimpleDateFormat("yyyyMMdd").parse(occurenceTo)).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addBankDetails(new BankDetails("777666555", "DE4321"))).setOwnTaxID("4711").setOwnVATID("DE19990815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setAdditionalAddress("Hinterhaus 3").setContact(new Contact("nameRep", "phoneRep", "emailRep@test.com"))).setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0))));
} catch (ParseException ex) {
throw new RuntimeException("Parse exception");
}
ze.setTransaction(new Invoice().setDueDate(sdf.parse("2020-12-12")).setIssueDate(sdf.parse("2020-11-21")).setDeliveryDate(sdf.parse("2020-11-10"))
.setSender(new TradeParty(orgname, "Ecke 12", "12345", "Stadthausen", "DE").addBankDetails(new BankDetails("DE88200800000970375700", "COBADEFFXXX").setAccountName("Max Mustermann")).addVATID("DE136695976"))
.setRecipient(new TradeParty("Theodor Est", "Bahnstr. 42", "88802", "Spielkreis", "DE")
.setContact(new Contact("Ingmar N. Fo", "(555) 23 78-23", "info@localhost.local")).setID("2"))
.setNumber(number)
.setReferenceNumber("AB321")
.addItem(new Item(new Product("Design (hours)", "Of a sample invoice", "HUR", new BigDecimal(7)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Ballons", "various colors, ~2000ml", "H87", new BigDecimal(19)), new BigDecimal("0.79"), new BigDecimal(400.0)))
.addItem(new Item(new Product("Hot air „heiße Luft“ (litres)", "", "LTR", new BigDecimal(19)), new BigDecimal("0.025"), new BigDecimal(800.0)))
);
ze.export(TARGET_PDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
} catch (IOException | ParseException e) {
fail("Exception should not be raised in testPushExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
assertTrue(zi.getUTF8().contains("777666555")); //the iban
assertTrue(zi.getUTF8().contains("DE88200800000970375700")); //the iban
assertTrue(zi.getUTF8().contains("Max Mustermann")); //account holder
assertTrue(zi.getUTF8().contains("<rsm:CrossIndustryInvoice"));
assertTrue(zi.getUTF8().contains("EUR")); //default invoice currency
assertTrue(zi.getUTF8().contains(occurenceFrom));
assertTrue(zi.getUTF8().contains(occurenceTo));
assertTrue(zi.getUTF8().contains(contractID));
assertTrue(zi.getUTF8().contains("Hinterhaus")); // lineTwo/additionalAddress
assertTrue(zi.getUTF8().contains("0815"));
assertTrue(zi.getUTF8().contains("AB321"));
// Reading ZUGFeRD
assertEquals("1.19", zi.getAmount());
assertEquals("571.04", zi.getAmount());
assertEquals(zi.getHolder(), orgname);
assertEquals(zi.getForeignReference(), number);
try {
@@ -162,7 +164,7 @@ public class ZF2PushTest extends TestCase {
// .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setContact(new Contact("contact testname","123456","contact.testemail@example.org" ).setFax("0911623562"))).setNumber(number)
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562"))).setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1"))))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50))))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1))))
@@ -242,7 +244,13 @@ public class ZF2PushTest extends TestCase {
}
/***
* test the edge cases of the invoice class
*/
public void testPushEdge() {
String occurrenceFrom = "20201001";
String occurrenceTo = "20201005";
String contractID = "376zreurzu0983";
String orgname = "Test company";
String number = "123";
@@ -256,17 +264,18 @@ public class ZF2PushTest extends TestCase {
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
ze.setTransaction(new Invoice().setCurrency("CHF").addNote("document level 1/2").addNote("document level 2/2").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
.setDetailedDeliveryPeriod(new SimpleDateFormat("yyyyMMdd").parse(occurrenceFrom), new SimpleDateFormat("yyyyMMdd").parse(occurrenceTo))
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID(taxID).setID("0009845"))
.setDeliveryAddress(new TradeParty("just the other side of the street", "teststr.12a", "55232", "Entenhausen", "DE").addVATID("DE47110"))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setID("0008734").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE").setFax("++49555123456")))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(16)), price, new BigDecimal(1.0)).addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))))
.setContractReferencedDocument(contractID)
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setID("0008734").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE").setFax("++49555123456")).setAdditionalAddress("Hinterhaus 3"))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(16)), price, new BigDecimal(1.0)).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)))
.setDetailedDeliveryPeriod(sdf.parse("2020-01-01"),sdf.parse("2020-01-31"))
.setDeliveryDate(sdf.parse("2020-02-02")).setOwnVATID("DE0815").setNumber(number)
.setDeliveryDate(sdf.parse("2020-11-02")).setOwnVATID("DE0815").setNumber(number)
);
} catch (ParseException e) {
e.printStackTrace();
@@ -282,8 +291,16 @@ public class ZF2PushTest extends TestCase {
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PUSHEDGE);
assertTrue(zi.getUTF8().contains("Hinterhaus"));
assertTrue(zi.getUTF8().contains("0009845"));
assertTrue(zi.getUTF8().contains("0008734"));
assertTrue(zi.getUTF8().contains(occurrenceFrom));
assertTrue(zi.getUTF8().contains(occurrenceTo));
assertTrue(zi.getUTF8().contains(contractID));
assertTrue(zi.getUTF8().contains("20200113")); // to contain item delivery periods
assertTrue(zi.getUTF8().contains("20200115")); // to contain item delivery periods
assertTrue(zi.getUTF8().contains("item level 1/1"));
assertTrue(zi.getUTF8().contains("DE4711")); // the VAT ID should be there...
assertFalse(zi.getUTF8().contains("DE47110")); // but not the VAT ID of the shiptotradeparty

View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.0.0-alpha4-SNAPSHOT</version>
<version>2.0.2-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Mustang</name>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.0.0-alpha4-SNAPSHOT</version>
<version>2.0.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
@@ -11,7 +11,7 @@
<name>Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung)</name>
<packaging>jar</packaging>
<version>2.0.0-alpha4-SNAPSHOT</version>
<version>2.0.2-SNAPSHOT</version>
<repositories>
<repository>
<!-- for jargs -->
@@ -75,10 +75,7 @@
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.0.0-alpha4-SNAPSHOT</version>
<!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with
mvn install:install-file -Dfile=mustang-1.5.4-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.5.4 -Dpackaging=jar -DgeneratePom=true
-->
<version>2.0.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>

View File

@@ -12,7 +12,7 @@ import static org.xmlunit.assertj.XmlAssert.assertThat;
public class LibraryTest extends ResourceCase {
public void testLibraryPush() {
File tempFile = new File("../library/target/testout-ZF2Push.pdf");
File tempFile = new File("../library/target/testout-MustangGnuaccountingBeispielRE-20201121_508.pdf");
assertTrue(tempFile.exists());
ZUGFeRDValidator zfv = new ZUGFeRDValidator();