diff --git a/History.md b/History.md
index 6fdc6d49..193f7bf3 100644
--- a/History.md
+++ b/History.md
@@ -1,3 +1,6 @@
+- upgraded en16931 validation to 1.3.8
+- Be able to embed Cross Industry Delivery Advice
+- update xr to v. 2.2
2.5.0
=======
2022-04-07
diff --git a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java
index 60eea2d4..5c9c2363 100755
--- a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java
+++ b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java
@@ -580,7 +580,7 @@ public class Main {
if (format == null) {
try {
- format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD, ox=Order-X)", "zf", "fx|zf|ox|dx");
+ format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD, ox=Order-X, da=Cross Industry Despatch Advice)", "zf", "fx|zf|ox|da");
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
@@ -603,7 +603,7 @@ public class Main {
try {
if ((format.equals("zf") && (zfIntVersion == 1)) || (format.equals("ox") )) {
zfProfile = getStringFromUser("Profile (b)asic, (c)omfort or ex(t)ended", "t", "B|b|C|c|T|t");
- } else if ( (format.equals("dx"))) {
+ } else if ( (format.equals("da"))) {
zfProfile = getStringFromUser("Profile (p)ilot", "p", "P|p");
} else {
zfProfile = getStringFromUser(
@@ -630,8 +630,8 @@ public class Main {
}
EStandard standard=EStandard.facturx;
- if (format.equals("dx")) {
- standard=EStandard.deliverx;
+ if (format.equals("da")) {
+ standard=EStandard.deliveradvice;
zfConformanceLevelProfile = Profiles.getByName(standard, "PILOT", 1);
}
@@ -682,7 +682,7 @@ public class Main {
((OXExporterFromA1)ze).ignorePDFAErrors();
}
- } else if (format.equals("dx")) {
+ } else if (format.equals("da")) {
ze = new DXExporterFromA1().setProducer("Mustang-cli")
.setZUGFeRDVersion(zfIntVersion)
.setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile);
diff --git a/library/src/main/java/org/mustangproject/EStandard.java b/library/src/main/java/org/mustangproject/EStandard.java
index 0326f7c8..6cf07237 100644
--- a/library/src/main/java/org/mustangproject/EStandard.java
+++ b/library/src/main/java/org/mustangproject/EStandard.java
@@ -1,6 +1,6 @@
package org.mustangproject;
public enum EStandard {
- facturx, orderx, deliverx, zugferd, cii, ubl
+ facturx, orderx, deliveradvice, zugferd, cii, ubl
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/DAPullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/DAPullProvider.java
new file mode 100644
index 00000000..5ef1d409
--- /dev/null
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/DAPullProvider.java
@@ -0,0 +1,358 @@
+/**
+ * *********************************************************************
+ *
+ * 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;
+
+import static org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat.DATE;
+import static org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants.CORRECTEDINVOICE;
+import static org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants.CATEGORY_CODES_WITH_EXEMPTION_REASON;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.Base64;
+import java.util.Date;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.mustangproject.*;
+
+public class DAPullProvider extends ZUGFeRD2PullProvider implements IXMLProvider {
+
+ protected IExportableTransaction trans;
+ private String paymentTermsDescription;
+ protected Profile profile = Profiles.getByName(EStandard.deliveradvice,"pilot", 1);
+
+
+ @Override
+ public void generateXML(IExportableTransaction trans) {
+ this.trans = trans;
+ boolean hasDueDate = false;
+ final SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
+
+ final String exemptionReason = "";
+
+ String senderReg = "";
+ if (trans.getOwnOrganisationFullPlaintextInfo() != null) {
+ senderReg = ""
+ + XMLTools.encodeXML(trans.getOwnOrganisationFullPlaintextInfo()) + ""
+ + "REG";
+
+ }
+
+ String subjectNote = "";
+ if (trans.getSubjectNote() != null) {
+ subjectNote = ""
+ + XMLTools.encodeXML(trans.getSubjectNote()) + ""
+ + "";
+ }
+
+ final String typecode = "220";
+ /*if (trans.getDocumentCode() != null) {
+ typecode = trans.getDocumentCode();
+ }*/
+ String notes = "";
+ if (trans.getNotes() != null) {
+ for (final String currentNote : trans.getNotes()) {
+ notes += "" + XMLTools.encodeXML(currentNote) + "";
+
+ }
+ }
+ String testBooleanStr="true";
+ String xml = "\n"
+ // + "
+ // xsi:schemaLocation=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100
+ // ../Schema/ZUGFeRD1p0.xsd\""
+ + ""
+ // + "
+ +" "+testBooleanStr+"\n"
+ //
+ + ""
+ + "" + getProfile().getID() + ""
+ + ""
+ + ""
+ + ""
+ + "" + XMLTools.encodeXML(trans.getNumber()) + ""
+ // + " RECHNUNG"
+ // + "380"
+ + "" + typecode + ""
+ + ""
+ + DATE.udtFormat(trans.getIssueDate()) + "" // date
+ + notes
+ + subjectNote
+ + senderReg
+
+ + ""
+ + "";
+ int lineID = 0;
+ for (final IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
+ lineID++;
+ if (currentItem.getProduct().getTaxExemptionReason() != null) {
+ // exemptionReason = "" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + "";
+ }
+ notes = "";
+ if (currentItem.getNotes() != null) {
+ for (final String currentNote : currentItem.getNotes()) {
+ notes = notes + "" + XMLTools.encodeXML(currentNote) + "";
+
+ }
+ }
+ final LineCalculator lc = new LineCalculator(currentItem);
+ xml += "" +
+ ""
+ + "" + lineID + ""
+ + notes
+ + ""
+
+ + "";
+ // + " 4012345001235"
+ if (currentItem.getProduct().getSellerAssignedID() != null) {
+ xml += ""
+ + XMLTools.encodeXML(currentItem.getProduct().getSellerAssignedID()) + "";
+ }
+ if (currentItem.getProduct().getBuyerAssignedID() != null) {
+ xml += ""
+ + XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "";
+ }
+ String allowanceChargeStr = "";
+ if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
+ for (final IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
+ allowanceChargeStr += getAllowanceChargeStr(allowance, currentItem);
+ }
+ }
+ if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
+ for (final IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
+ allowanceChargeStr += getAllowanceChargeStr(charge, currentItem);
+
+ }
+ }
+
+
+ xml += "" + XMLTools.encodeXML(currentItem.getProduct().getName()) + ""
+ + "" + XMLTools.encodeXML(currentItem.getProduct().getDescription())
+ + ""
+ + ""
+
+ + ""
+ + ""
+ + quantityFormat(currentItem.getQuantity()) + ""
+ + ""
+ + "";
+ if ((currentItem.getDetailedDeliveryPeriodFrom() != null) || (currentItem.getDetailedDeliveryPeriodTo() != null)) {
+ xml += "";
+ if (currentItem.getDetailedDeliveryPeriodFrom() != null) {
+ xml += "" + DATE.udtFormat(currentItem.getDetailedDeliveryPeriodFrom()) + "";
+ }
+ if (currentItem.getDetailedDeliveryPeriodTo() != null) {
+ xml += "" + DATE.udtFormat(currentItem.getDetailedDeliveryPeriodTo()) + "";
+ }
+ xml += "";
+
+ }
+
+ xml += ""
+ + "" + currencyFormat(lc.getItemTotalNetAmount())
+ + "" // currencyID=\"EUR\"
+ + "";
+ /* if (currentItem.getAdditionalReferencedDocumentID() != null) {
+ xml += "" + currentItem.getAdditionalReferencedDocumentID() + "130";
+
+ }*/
+ xml += ""
+ + "";
+
+ }
+
+ xml += "";
+ if (trans.getReferenceNumber() != null) {
+ xml += "" + XMLTools.encodeXML(trans.getReferenceNumber()) + "";
+
+ }
+ xml += ""
+ + getTradePartyAsXML(trans.getSender(), true, false)
+ + ""
+ + "";
+ // + " GE2020211"
+ // + " 4000001987658"
+
+ xml += getTradePartyAsXML(trans.getRecipient(), false, false);
+ xml += "";
+
+ if (trans.getSellerOrderReferencedDocumentID() != null) {
+ xml += ""
+ + ""
+ + XMLTools.encodeXML(trans.getSellerOrderReferencedDocumentID()) + ""
+ + "";
+ }
+ if (trans.getBuyerOrderReferencedDocumentID() != null) {
+ xml += ""
+ + ""
+ + XMLTools.encodeXML(trans.getBuyerOrderReferencedDocumentID()) + ""
+ + "";
+ }
+ if (trans.getContractReferencedDocument() != null) {
+ xml += ""
+ + ""
+ + XMLTools.encodeXML(trans.getContractReferencedDocument()) + ""
+ + "";
+ }
+
+ // Additional Documents of XRechnung (Rechnungsbegruendende Unterlagen - BG-24 XRechnung)
+ if (trans.getAdditionalReferencedDocuments() != null) {
+ for (final FileAttachment f : trans.getAdditionalReferencedDocuments()) {
+ final String documentContent = new String(Base64.getEncoder().encodeToString(f.getData()));
+ xml += ""
+ + "" + f.getFilename() + ""
+ + "916"
+ + "" + f.getDescription() + ""
+ + "" + documentContent + ""
+ + "";
+ }
+ }
+
+ if (trans.getSpecifiedProcuringProjectID() != null) {
+ xml += ""
+ + ""
+ + XMLTools.encodeXML(trans.getSpecifiedProcuringProjectID()) + "";
+ if (trans.getSpecifiedProcuringProjectName() != null) {
+ xml += "" + XMLTools.encodeXML(trans.getSpecifiedProcuringProjectName()) + "";
+ }
+ xml += "";
+ }
+ xml += ""
+ + "";
+ if (this.trans.getDeliveryAddress() != null) {
+ xml += "" +
+ getTradePartyAsXML(this.trans.getDeliveryAddress(), false, true) +
+ "";
+ }
+ xml += " \n" +
+ " \n" +
+ " "+ DATE.udtFormat(trans.getDeliveryDate() )+"\n" +
+ " \n" +
+ " ";
+
+/*
+ xml += ""
+ + "";
+
+ if (trans.getDeliveryDate() != null) {
+ xml += DATE.udtFormat(trans.getDeliveryDate());
+ } else {
+ throw new IllegalStateException("No delivery date provided");
+ }
+ xml += "\n";
+ xml += "\n"
+
+ */
+ /*
+ * + "\n" +
+ * "20130603\n" +
+ * "2013-51112\n" +
+ * "\n"
+ */
+ xml+= "\n";
+ // + " "
+ // + " "
+ // + " "
+ // + " Wir erlauben uns Ihnen folgende Positionen aus der Lieferung Nr.
+ // 2013-51112 in Rechnung zu stellen:\n"
+ // + " \n"
+ // + " \n"
+ // + " \n";
+
+ xml += ""
+ + "";
+
+ final byte[] zugferdRaw;
+ try {
+ zugferdRaw = xml.getBytes("UTF-8");
+
+ zugferdData = XMLTools.removeBOM(zugferdRaw);
+ } catch (final UnsupportedEncodingException e) {
+ Logger.getLogger(OXPullProvider.class.getName()).log(Level.SEVERE, null, e);
+ }
+ }
+
+
+ @Override
+ public void setProfile(Profile p) {
+ profile = p;
+ }
+
+ @Override
+ public Profile getProfile() {
+ return profile;
+ }
+
+ private String buildPaymentTermsXml() {
+
+ final IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
+ if (paymentTerms == null) {
+ return "";
+ }
+ String paymentTermsXml = "";
+
+ final IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
+ final Date dueDate = paymentTerms.getDueDate();
+ if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) {
+ throw new IllegalStateException(
+ "if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
+ }
+ paymentTermsXml += "" + paymentTerms.getDescription() + "";
+ if (dueDate != null) {
+ paymentTermsXml += "";
+ paymentTermsXml += DATE.udtFormat(dueDate);
+ paymentTermsXml += "";
+ }
+
+ if (discountTerms != null) {
+ paymentTermsXml += "";
+ final String currency = trans.getCurrency();
+ final String basisAmount = currencyFormat(calc.getGrandTotal());
+ paymentTermsXml += "" + basisAmount + "";
+ paymentTermsXml += "" + discountTerms.getCalculationPercentage().toString()
+ + "";
+
+ if (discountTerms.getBaseDate() != null) {
+ final Date baseDate = discountTerms.getBaseDate();
+ paymentTermsXml += "";
+ paymentTermsXml += DATE.udtFormat(baseDate);
+ paymentTermsXml += "";
+
+ paymentTermsXml += ""
+ + discountTerms.getBasePeriodMeasure() + "";
+ }
+
+ paymentTermsXml += "";
+ }
+
+ paymentTermsXml += "";
+ return paymentTermsXml;
+ }
+
+
+}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/DXExporterFromA3.java b/library/src/main/java/org/mustangproject/ZUGFeRD/DXExporterFromA3.java
index 11fdfc15..7ba37681 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/DXExporterFromA3.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/DXExporterFromA3.java
@@ -105,7 +105,7 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* OrderX document type. As of version 1.0 it may be
* ORDER, ORDER_RESPONSE, or ORDER_CHANGE
*/
- protected String deliverXDocumentType = "DESPATCHADVICE";
+ protected String despatchAdviceDocumentType = "DESPATCHADVICE";
private HashMap additionalXMLs = new HashMap();
@@ -404,7 +404,7 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
*/
public DXExporterFromA3 setDocumentType(String DocumentType)
{
- this.deliverXDocumentType = DocumentType;
+ this.despatchAdviceDocumentType = DocumentType;
return this;
}
@@ -428,7 +428,7 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, 1, true, xmlProvider.getProfile(),
"urn:facturx:pdfa:CrossIndustryDocument:despatchadvice:1p0#", "fx",
"cida.xml");
- zf.setType(this.deliverXDocumentType);
+ zf.setType(this.despatchAdviceDocumentType);
metadata.addSchema(zf);
// also add the schema extensions...
@@ -679,7 +679,7 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
@Override
public DXExporterFromA3 setZUGFeRDVersion(int version) {
- OXPullProvider z2p = new OXPullProvider();
+ DAPullProvider z2p = new DAPullProvider();
setXMLProvider(z2p);
return this;
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/Profiles.java b/library/src/main/java/org/mustangproject/ZUGFeRD/Profiles.java
index 2e81bb18..8f22805e 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/Profiles.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/Profiles.java
@@ -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.1")}
+ {"XRECHNUNG", new Profile("XRECHNUNG", "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2")}
}).collect(Collectors.toMap(data -> (String) data[0], data -> (Profile) data[1]));
static Map zf1Map = Stream.of(new Object[][]{
@@ -51,7 +51,7 @@ public class Profiles {
}).collect(Collectors.toMap(data -> (String) data[0], data -> (Profile) data[1]));
static Map dx1Map = Stream.of(new Object[][]{
- {"PILOT", new Profile("PILOT", "urn:facturx:pdfa:CrossIndustryDocument:despatchadvice:1p0#")}
+ {"PILOT", new Profile("PILOT", "urn:awv-net.de:CIDA:1.0:pilot")}
}).collect(Collectors.toMap(data -> (String) data[0], data -> (Profile) data[1]));
@@ -63,7 +63,7 @@ public class Profiles {
throw new RuntimeException("Profile not found");
}
return result;
- } else if (standard == EStandard.deliverx) {
+ } else if (standard == EStandard.deliveradvice) {
Profile result = null;
result = dx1Map.get(name.toUpperCase());
if (result == null) {
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/DXTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/DXTest.java
index 98db1729..ec4409b5 100644
--- a/library/src/test/java/org/mustangproject/ZUGFeRD/DXTest.java
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/DXTest.java
@@ -23,9 +23,13 @@ import junit.framework.Test;
import junit.framework.TestSuite;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
+import org.mustangproject.EStandard;
import org.mustangproject.Invoice;
+import org.mustangproject.TradeParty;
import javax.xml.xpath.XPathExpressionException;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
@@ -38,6 +42,8 @@ import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
+import static org.xmlunit.assertj.XmlAssert.assertThat;
+
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class DXTest extends MustangReaderTestCase implements IExportableTransaction {
final String TARGET_PDF = "./target/testout-DX.pdf";
@@ -198,10 +204,10 @@ public class DXTest extends MustangReaderTestCase implements IExportableTransact
EdgeProduct designProduct = new EdgeProduct("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung",
"HUR");
EdgeProduct balloonProduct = new EdgeProduct("", "Bestellerweiterung für E&F Umbau", "C62");// test for issue
- // 103
+ // 103
EdgeProduct airProduct = new EdgeProduct("", "Heiße Luft pro Liter", "LTR");
- Item design=new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
+ Item design = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
design.setAddReference("1825");
allItems[0] = design;
allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct);
@@ -268,8 +274,8 @@ public class DXTest extends MustangReaderTestCase implements IExportableTransact
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
DXExporterFromA1 oe = new DXExporterFromA1().setProducer("My Application")
- .setCreator(System.getProperty("user.name")).setZUGFeRDVersion(1).ignorePDFAErrors()
- .load(SOURCE_PDF)) {
+ .setCreator(System.getProperty("user.name")).setZUGFeRDVersion(1).ignorePDFAErrors()
+ .load(SOURCE_PDF)) {
oe.setTransaction(this);
String theXML = new String(oe.getProvider().getXML(), StandardCharsets.UTF_8);
assertTrue(theXML.contains("