diff --git a/History.md b/History.md
index 4a4c67a6..21dc49d3 100644
--- a/History.md
+++ b/History.md
@@ -1,6 +1,30 @@
-- #678
-- #679
-- #681
+#705
+#707
+-#708
+-#709
+607
+649
+650
+665
+684
+703
+701
+691
+
+
+
+
+
+2.16.1
+=======
+2025-01-21
+- #678 some ubl creditnote attributes are not parsed
+- #679 validation of a XR does not ignore whitespace
+- #681 IBAN assigned to invoice sender not recipient on direct debit
+- #689 incorrect element order when both charge reason and reasoncode are specified
+- be able to set detailedDeliveryPeriodFrom, detailedDeliveryPeriodTo MS188
+- updated verapdf from 1.26.1 to 1.26.2
+- cashDiscount JSON now corrently ignores values for cii and xr methods
2.16.0
=======
diff --git a/Mustang-CLI/pom.xml b/Mustang-CLI/pom.xml
index 9d83688f..d5b924e9 100644
--- a/Mustang-CLI/pom.xml
+++ b/Mustang-CLI/pom.xml
@@ -3,7 +3,7 @@
org.mustangproject
core
- 2.16.1-SNAPSHOT
+ 2.16.2-SNAPSHOT
4.0.0
org.mustangproject
@@ -12,7 +12,7 @@
should also work for XRechnung/CII.
jar
- 2.16.1-SNAPSHOT
+ 2.16.2-SNAPSHOT
UTF-8
11
@@ -23,7 +23,7 @@
org.mustangproject
validator
- 2.16.1-SNAPSHOT
+ 2.16.2-SNAPSHOT
diff --git a/library/pom.xml b/library/pom.xml
index 81a1716f..91695791 100644
--- a/library/pom.xml
+++ b/library/pom.xml
@@ -3,13 +3,13 @@
org.mustangproject
core
- 2.16.1-SNAPSHOT
+ 2.16.2-SNAPSHOT
4.0.0
org.mustangproject
library
- 2.16.1-SNAPSHOT
+ 2.16.2-SNAPSHOT
jar
Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII)
FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT
@@ -59,6 +59,12 @@
slf4j-api
2.0.9
+
+ net.sf.offo
+ fop-hyph
+ 2.0
+ runtime
+
net.sf.saxon
diff --git a/library/src/main/java/org/mustangproject/CashDiscount.java b/library/src/main/java/org/mustangproject/CashDiscount.java
index 2151489a..b1993a02 100644
--- a/library/src/main/java/org/mustangproject/CashDiscount.java
+++ b/library/src/main/java/org/mustangproject/CashDiscount.java
@@ -1,5 +1,6 @@
package org.mustangproject;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IZUGFeRDCashDiscount;
@@ -63,6 +64,7 @@ public class CashDiscount implements IZUGFeRDCashDiscount {
/***
* @return this particular cash discount as cross industry invoice XML
*/
+ @JsonIgnore
public String getAsCII() {
return ""+
"Cash Discount"+
@@ -78,6 +80,7 @@ public class CashDiscount implements IZUGFeRDCashDiscount {
* XRechnung CIUS defined it's own proprietary format for a freetext field
* @return this particular cash discount in proprietary xrechnung format
*/
+ @JsonIgnore
public String getAsXRechnung() {
return "#SKONTO#TAGE="+days+"#PROZENT="+XMLTools.nDigitFormat(percent,2)+"#\n";
}
diff --git a/library/src/main/java/org/mustangproject/Invoice.java b/library/src/main/java/org/mustangproject/Invoice.java
index 04c8b5dc..a03487ae 100644
--- a/library/src/main/java/org/mustangproject/Invoice.java
+++ b/library/src/main/java/org/mustangproject/Invoice.java
@@ -69,6 +69,7 @@ public class Invoice implements IExportableTransaction {
protected String vatDueDateTypeCode = null;
protected String creditorReferenceID; // required when direct debit is used.
private BigDecimal roundingAmount=null;
+ private String paymentReference; // Remittance information / Verwendungszweck, BT-83
public Invoice() {
ZFItems = new ArrayList<>();
@@ -650,6 +651,16 @@ public class Invoice implements IExportableTransaction {
return this;
}
+ @Override
+ public String getPaymentReference() {
+ return paymentReference;
+ }
+
+ public Invoice setPaymentReference(String paymentReference) {
+ this.paymentReference = paymentReference;
+ return this;
+ }
+
@Override
public TradeParty getDeliveryAddress() {
return deliveryAddress;
@@ -783,11 +794,20 @@ public class Invoice implements IExportableTransaction {
return detailedDeliveryDateStart;
}
+ public Invoice setDetailedDeliveryPeriodFrom(Date dt) {
+ detailedDeliveryDateStart=dt;
+ return this;
+ }
+
@Override
public Date getDetailedDeliveryPeriodTo() {
return detailedDeliveryPeriodEnd;
}
+ public Invoice setDetailedDeliveryPeriodTo(Date dt) {
+ detailedDeliveryPeriodEnd=dt;
+ return this;
+ }
/**
* adds a free text paragraph, which will become an includedNote element
diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java
index 94562ca5..0688530a 100644
--- a/library/src/main/java/org/mustangproject/Item.java
+++ b/library/src/main/java/org/mustangproject/Item.java
@@ -172,6 +172,9 @@ public class Item implements IZUGFeRDExportableItem {
icnm.getAsNodeMap("ApplicableTradeTax")
.flatMap(cnm -> cnm.getAsBigDecimal("RateApplicablePercent", "ApplicablePercent"))
.ifPresent(product::setVATPercent);
+ icnm.getAsNodeMap("ApplicableTradeTax")
+ .flatMap(cnm -> cnm.getAsString("ExemptionReason"))
+ .ifPresent(product::setTaxExemptionReason);
icnm.getAsNodeMap("SpecifiedTradeAllowanceCharge").ifPresent(stac -> {
stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> {
String isChargeString=ci.getAsString("Indicator").get();
@@ -187,8 +190,12 @@ public class Item implements IZUGFeRDExportableItem {
if (amountString!=null) {
izac.setTotalAmount(new BigDecimal(amountString));
}
+ if(percentString!=null) {
izac.setPercent(new BigDecimal(percentString));
+ }
+ if(reason!=null) {
izac.setReason(reason);
+ }
if (isChargeString.equalsIgnoreCase("false")) {
addAllowance(izac);
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java
index 0a013ba3..686afd44 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java
@@ -314,6 +314,10 @@ public interface IExportableTransaction {
return null;
}
+ default String getPaymentReference() {
+ return null;
+ }
+
/**
* returns if a rebate agreements exists
*
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java
index 2903d81d..6958bb61 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java
@@ -288,8 +288,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
final String allowanceChargeStr = "" +
chargeIndicator + "" + percentage +
"" + priceFormat(allowance.getTotalAmount(item)) + "" +
- reason +
reasonCode +
+ reason +
"";
return allowanceChargeStr;
}
@@ -323,8 +323,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
final String itemTotalAllowanceChargeStr = "" +
chargeIndicator + "" + percentage +
"" + currencyFormat(allowance.getTotalAmount(item)) + "" +
- reason +
reasonCode +
+ reason +
"";
return itemTotalAllowanceChargeStr;
}
@@ -388,14 +388,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ ""
+ ""
+ ""
- + "" + XMLTools.encodeXML(trans.getNumber()) + ""
- // + "RECHNUNG"
- // + "380"
- + "" + typecode + ""
- + ""
- + DATE.udtFormat(trans.getIssueDate()) + "" // date
+ + "" + XMLTools.encodeXML(trans.getNumber()) + "";
+ if (profile == Profiles.getByName("Extended") && trans.getDocumentName() != null) {
+ xml += "" + XMLTools.encodeXML(trans.getDocumentName()) + "";
+ }
+ xml += "" + typecode + ""
+ + "" + DATE.udtFormat(trans.getIssueDate()) + "" // date
+ buildNotes(trans)
-
+ ""
+ "";
int lineID = 0;
@@ -662,8 +661,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if ((trans.getCreditorReferenceID() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
xml += "" + XMLTools.encodeXML(trans.getCreditorReferenceID()) + "";
}
- if ((trans.getNumber() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
- xml += "" + XMLTools.encodeXML(trans.getNumber()) + "";
+ if ((trans.getPaymentReference() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
+ xml += "" + XMLTools.encodeXML(trans.getPaymentReference()) + "";
}
xml += "" + trans.getCurrency() + "";
if (this.trans.getPayee() != null) {
@@ -744,12 +743,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
"true" +
"" +
"" + currencyFormat(charge.getTotalAmount(calc)) + "";
- if (charge.getReason() != null) {
- xml += "" + XMLTools.encodeXML(charge.getReason()) + "";
- }
if (charge.getReasonCode() != null) {
xml += "" + charge.getReasonCode() + "";
}
+ if (charge.getReason() != null) {
+ xml += "" + XMLTools.encodeXML(charge.getReason()) + "";
+ }
xml += "" +
"VAT" +
"" + charge.getCategoryCode() + "";
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java
index 9115feb4..734f5f0c 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java
@@ -288,6 +288,7 @@ public class ZUGFeRDInvoiceImporter {
public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseException {
String number = "";
+ String documentName = null;
String typeCode = null;
String deliveryPeriodStart = null;
String deliveryPeriodEnd = null;
@@ -496,6 +497,9 @@ public class ZUGFeRDInvoiceImporter {
if ((item.getLocalName() != null) && (item.getLocalName().equals("ID"))) {
number = XMLTools.trimOrNull(item);
}
+ if ((item.getLocalName() != null) && (item.getLocalName().equals("Name"))) {
+ documentName = XMLTools.trimOrNull(item);
+ }
if ((item.getLocalName() != null) && (item.getLocalName().equals("TypeCode"))) {
typeCode = XMLTools.trimOrNull(item);
}
@@ -556,13 +560,13 @@ public class ZUGFeRDInvoiceImporter {
}
zpp.addNotes(includedNotes);
String rootNode = extractString("local-name(/*)");
- if (rootNode.equals("Invoice")||rootNode.equals("CreditNote")) {
+ if (rootNode.equals("Invoice") || rootNode.equals("CreditNote")) {
// UBL...
// //*[local-name()="Invoice" or local-name()="CreditNote"]
number = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"ID\"]").trim();
typeCode = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"InvoiceTypeCode\"]").trim();
String issueDateStr = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"IssueDate\"]").trim();
- if (issueDateStr.length()>0) {
+ if (issueDateStr.length() > 0) {
issueDate = new SimpleDateFormat("yyyy-MM-dd").parse(issueDateStr);
}
String dueDt = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"DueDate\"]").trim();
@@ -651,7 +655,7 @@ public class ZUGFeRDInvoiceImporter {
zpp.setCurrency(currency);
String paymentTermsDescription = extractString("//*[local-name()=\"SpecifiedTradePaymentTerms\"]/*[local-name()=\"Description\"]|//*[local-name()=\"PaymentTerms\"]/*[local-name()=\"Note\"]");
- if ((paymentTermsDescription!=null)&&(!paymentTermsDescription.isEmpty())) {
+ if ((paymentTermsDescription != null) && (!paymentTermsDescription.isEmpty())) {
zpp.setPaymentTermDescription(paymentTermsDescription);
}
@@ -668,6 +672,12 @@ public class ZUGFeRDInvoiceImporter {
NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes();
for (int settlementChildIndex = 0; settlementChildIndex < headerTradeSettlementChilds.getLength(); settlementChildIndex++) {
+ if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
+ && (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("PaymentReference"))) {
+ String paymentReference = headerTradeSettlementChilds.item(settlementChildIndex).getTextContent();
+ zpp.setPaymentReference(paymentReference);
+ }
+
if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
&& (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("SpecifiedTradePaymentTerms"))) {
NodeList paymentTermChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes();
@@ -802,7 +812,7 @@ public class ZUGFeRDInvoiceImporter {
}
- zpp.setIssueDate(issueDate).setDueDate(dueDate).setDeliveryDate(deliveryDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentCode(typeCode);
+ zpp.setIssueDate(issueDate).setDueDate(dueDate).setDeliveryDate(deliveryDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentName(documentName).setDocumentCode(typeCode);
if ((directDebitMandateID != null) && (IBAN != null)) {
DirectDebit d = new DirectDebit(IBAN, directDebitMandateID);
@@ -848,15 +858,14 @@ public class ZUGFeRDInvoiceImporter {
Node currentItemNode = nodes.item(i);
ReferencedDocument doc = ReferencedDocument.fromNode(currentItemNode);
- if (doc != null
- && (!Objects.equals(zpp.getInvoiceReferencedDocumentID(), doc.getIssuerAssignedID())
- || !Objects.equals(zpp.getInvoiceReferencedIssueDate(), doc.getFormattedIssueDateTime())))
- {
+ if (doc != null
+ && (!Objects.equals(zpp.getInvoiceReferencedDocumentID(), doc.getIssuerAssignedID())
+ || !Objects.equals(zpp.getInvoiceReferencedIssueDate(), doc.getFormattedIssueDateTime()))) {
zpp.addInvoiceReferencedDocument(doc);
}
}
}
-
+
zpp.setOwnOrganisationName(extractString("//*[local-name()=\"SellerTradeParty\"]/*[local-name()=\"Name\"]|//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyName\"]").trim());
String rounding = extractString("//*[local-name()=\"SpecifiedTradeSettlementHeaderMonetarySummation\"]/*[local-name()=\"RoundingAmount\"]|//*[local-name()=\"LegalMonetaryTotal\"]/*[local-name()=\"Party\"]/*[local-name()=\"PayableRoundingAmount\"]");
@@ -890,7 +899,7 @@ public class ZUGFeRDInvoiceImporter {
xpr = xpath.compile("//*[local-name()=\"AttachmentBinaryObject\"]|//*[local-name()=\"EmbeddedDocumentBinaryObject\"]");
NodeList attachmentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < attachmentNodes.getLength(); i++) {
- FileAttachment fa = new FileAttachment(attachmentNodes.item(i).getAttributes().getNamedItem("filename").getNodeValue(), attachmentNodes.item(i).getAttributes().getNamedItem("mimeCode").getNodeValue(), "Data", Base64.getDecoder().decode(XMLTools.trimOrNull(attachmentNodes.item(i))));
+ FileAttachment fa = new FileAttachment(attachmentNodes.item(i).getAttributes().getNamedItem("filename").getNodeValue(), attachmentNodes.item(i).getAttributes().getNamedItem("mimeCode").getNodeValue(), "Data", Base64.getMimeDecoder().decode(XMLTools.trimOrNull(attachmentNodes.item(i))));
zpp.embedFileInXML(fa);
// filename = "Aufmass.png" mimeCode = "image/png"
//EmbeddedDocumentBinaryObject cbc:EmbeddedDocumentBinaryObject mimeCode="image/png" filename="Aufmass.png"
@@ -976,6 +985,38 @@ public class ZUGFeRDInvoiceImporter {
}
}
+ xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"SpecifiedLogisticsServiceCharge\"]");// UBL unknown
+ chargeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
+ for (int i = 0; i < chargeNodes.getLength(); i++) {
+ NodeList chargeNodeChilds = chargeNodes.item(i).getChildNodes();
+ String chargeAmount = null;
+ String taxPercent = null;
+ for (int chargeChildIndex = 0; chargeChildIndex < chargeNodeChilds.getLength(); chargeChildIndex++) {
+ String chargeChildName = chargeNodeChilds.item(chargeChildIndex).getLocalName();
+ if (chargeChildName != null) {
+ if (chargeChildName.equals("AppliedAmount")) {
+ chargeAmount = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
+ } else if (chargeChildName.equals("AppliedTradeTax")) {
+ NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes();
+ for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
+ String taxItemName = taxChilds.item(taxChildIndex).getLocalName();
+ if ((taxItemName != null) && (taxItemName.equals("RateApplicablePercent"))) {
+ taxPercent = XMLTools.trimOrNull(taxChilds.item(taxChildIndex));
+ }
+ }
+ }
+ }
+ //appliedAmount
+ //AppliedTradeTax
+ }
+ if (chargeAmount != null) {
+ Charge c = new Charge(new BigDecimal(chargeAmount));
+ if (taxPercent != null) {
+ c.setTaxPercent(new BigDecimal(taxPercent));
+ }
+ zpp.addCharge(c);
+ }
+ }
TransactionCalculator tc = new TransactionCalculator(zpp);
@@ -1040,7 +1081,7 @@ public class ZUGFeRDInvoiceImporter {
} else if (rootNode.equals("Invoice")) {
return EStandard.ubl;
} else if (rootNode.equals("CreditNote")) {
- return EStandard.ubl;
+ return EStandard.ubl_creditnote;
} else if (rootNode.equals("CrossIndustryInvoice")) {
return EStandard.facturx;
} else if (rootNode.equals("SCRDMCCBDACIDAMessageStructure")) {
@@ -1085,11 +1126,17 @@ public class ZUGFeRDInvoiceImporter {
*
* @return the file attachments embedded in XML (using base64) decoded as byte array,
* for PDF embedded files in FX use getFileAttachmentsPDF()
+ * may return empty array
* @deprecated use invoice.getAdditionalReferencedDocuments
*/
@Deprecated
public List getFileAttachmentsXML() {
- return new ArrayList<>(Arrays.asList(importedInvoice.getAdditionalReferencedDocuments()));
+ if (importedInvoice.getAdditionalReferencedDocuments()!=null) {
+ return new ArrayList<>(Arrays.asList(importedInvoice.getAdditionalReferencedDocuments()));
+ } else {
+ return new ArrayList<>();
+ }
+
}
/***
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java
index 9b5c1e73..8795b478 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java
@@ -45,6 +45,9 @@ import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
public class ZUGFeRDVisualizer {
@@ -254,16 +257,61 @@ public class ZUGFeRDVisualizer {
// the writing part
File XMLinputFile = new File(xmlFilename);
- String result = null;
+ String fopInput = null;
/* remove file endings so that tests can also pass after checking
out from git with arbitrary options (which may include CSRF changes)
*/
try {
- result = this.toFOP(XMLinputFile.getAbsolutePath());
+ fopInput = this.toFOP(XMLinputFile.getAbsolutePath());
} catch (TransformerException | IOException e) {
LOGGER.error("Failed to apply FOP", e);
}
+
+ toPDFfromFOP(fopInput, () -> {
+ try {
+ return new FileOutputStream(pdfFilename);
+ } catch (FileNotFoundException e) {
+ LOGGER.error("Failed to create PDF", e);
+ }
+ return null;
+ }, (OutputStream out) -> {});
+ }
+
+ public byte[] toPDF(String xmlContent) {
+
+ String fopInput = null;
+
+ /* remove file endings so that tests can also pass after checking
+ out from git with arbitrary options (which may include CSRF changes)
+ */
+ try {
+ ByteArrayInputStream fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));
+ EStandard theStandard = findOutStandardFromRootNode(fis);
+ fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));//rewind :-(
+
+ fopInput = toFOP(fis, theStandard);
+ } catch (TransformerException | IOException e) {
+ LOGGER.error("Failed to apply FOP", e);
+ }
+
+ AtomicReference byteHolder = new AtomicReference<>();
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ toPDFfromFOP(fopInput, () -> new BufferedOutputStream(os), (OutputStream out) -> {
+
+ try {
+ out.flush();
+ } catch (IOException e) {
+ LOGGER.error("Failed to create PDF", e);
+ }
+ byteHolder.set(os.toByteArray());
+ });
+
+ return byteHolder.get();
+ }
+
+ private void toPDFfromFOP(String fopInput, Supplier outputStreamDelegate, Consumer consumerDelegate) {
+
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
Configuration cfg = null;
@@ -291,7 +339,7 @@ public class ZUGFeRDVisualizer {
// Step 2: Set up output stream.
// Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams).
- try (OutputStream out = new BufferedOutputStream(new FileOutputStream(pdfFilename))) {
+ try (OutputStream out = new BufferedOutputStream(outputStreamDelegate.get())) {
// Step 3: Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out);
@@ -302,13 +350,15 @@ public class ZUGFeRDVisualizer {
// Step 5: Setup input and output for XSLT transformation
// Setup input stream
- Source src = new StreamSource(new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8)));
+ Source src = new StreamSource(new ByteArrayInputStream(fopInput.getBytes(StandardCharsets.UTF_8)));
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Step 6: Start XSLT transformation and FOP processing
transformer.transform(src, res);
+
+ consumerDelegate.accept(out);
} catch (FOPException | IOException | TransformerException e) {
LOGGER.error("Failed to create PDF", e);
diff --git a/library/src/main/resources/stylesheets/result-pdf.xsl b/library/src/main/resources/stylesheets/result-pdf.xsl
index 0dfa7c95..f3e2e0d4 100644
--- a/library/src/main/resources/stylesheets/result-pdf.xsl
+++ b/library/src/main/resources/stylesheets/result-pdf.xsl
@@ -28,6 +28,14 @@
red
+
+
+ Das XML ist valide.
+
+
+ Das XML ist nicht valide.
+
+
green
@@ -37,18 +45,26 @@
-
+
Das ZUGFeRD-PDF ist valide.
-
+
Das ZUGFeRD-PDF ist nicht valide.
+
+
+ green
+
+
+ red
+
+
-
+
Es wird empfohlen, das Dokument anzunehmen und es weiterzuverarbeiten.
-
+
Es wird empfohlen, das Dokument zurückzuweisen.
@@ -118,6 +134,7 @@
+
+
+
+
+
+
+
+
+ true
+
+
+ urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
+
+
+
+ R87654321012345
+ WARENRECHNUNG
+ 380
+
+ 20180806
+
+
+ ST3
+ Es bestehen Rabatt- oder Bonusvereinbarungen.
+ AAK
+
+
+ EEV
+ Der Verkäufer bleibt Eigentümer der Waren bis zu vollständigen Erfüllung der Kaufpreisforderung.
+ AAJ
+
+
+ MUSTERLIEFERANT GMBH
+BAHNHOFSTRASSE 99
+99199 MUSTERHAUSEN
+Geschäftsführung:
+Max Mustermann
+USt-IdNr: DE123456789
+Telefon: +49 932 431 0
+www.musterlieferant.de
+HRB Nr. 372876
+Amtsgericht Musterstadt
+GLN 4304171000002
+WEEE-Reg-Nr.: DE87654321
+
+ REG
+
+
+ Leergutwert: 46,50
+
+
+ Wichtige Information: Bei Bestellungen bis zum 19.12. ist die Auslieferung bis spätestens 23.12. garantiert.
+
+
+
+
+
+ 1
+
+
+ 4123456000014
+ ZS997
+ Zitronensäure 100ml
+
+ Verpackungsart
+ BO
+
+
+
+
+ 1.0000
+
+
+ 1.0000
+
+
+
+ 100.0000
+ 4.0000
+
+
+
+ VAT
+ S
+ 19.00
+
+
+ 100.00
+
+
+
+
+
+ 2
+
+
+ 4123456000021
+ GZ250
+ Gelierzucker Extra 250g
+
+
+
+ 1.5000
+
+
+ false
+
+ 0.0300
+ Artikelrabatt 1
+
+
+
+ false
+
+ 0.0200
+ Artikelrabatt 2
+
+
+
+ 1.4500
+
+
+
+ 50.0000
+ 1.0000
+
+
+
+ VAT
+ S
+ 7.00
+
+
+ 72.50
+
+
+
+
+
+ 3
+
+
+ 4123456000021
+ GZ250
+ Gelierzucker Extra 250g
+ Artikel wie vereinbart ohne Berechnung
+
+
+
+ 0.0000
+
+
+ 0.0000
+
+
+
+ 10.0000
+ 1.0000
+
+
+
+ VAT
+ S
+ 7.00
+
+
+ 0.00
+
+
+
+
+
+ 4
+
+
+ 4100130013294
+ 2031
+
+ Bierbrau Pils 20/0500
+ EAN-VKE: 4100130913297
+
+ Verpackung
+ Kiste
+
+
+
+
+ 12.0000
+
+
+ 12.0000
+
+
+
+ 15.0000
+ 20.0000
+
+
+
+ VAT
+ S
+ 19.00
+
+
+ 180.00
+
+
+
+
+
+ 5
+
+
+ 2001015001325
+ 1805
+
+ Leergutpfand 20 x 0,5l
+
+ Verpackung
+ unverpackt
+
+
+
+
+ 3.1000
+
+
+ 3.1000
+
+
+
+ 15.0000
+ 1.0000
+
+
+
+ VAT
+ S
+ 19.00
+
+
+ 46.50
+
+
+
+
+
+ 6
+
+
+ 4123456000038
+ MP107
+ Mischpalette Joghurt Karton 3 x 20
+
+ Verpackung
+ Karton
+
+
+ 4123456001035
+ JOG103
+ Erdbeer 20 x 150g Becher
+ 20.0000
+
+
+ 4123456002032
+ JOG203
+ Banane 20 x 150g Becher
+ 20.0000
+
+
+ 4123456003039
+ JOG303
+ Schoko 20 x 150g Becher
+ 20.0000
+
+
+
+
+ 30.0000
+
+
+ false
+
+ 0.9000
+ Artikelrabatt 1
+
+
+
+ 29.1000
+
+
+
+ 2.0000
+ 1.0000
+
+
+
+ VAT
+ S
+ 7.00
+
+
+ 58.20
+
+
+
+
+
+ 549910
+ 4333741000005
+ MUSTERLIEFERANT GMBH
+
+
+ +49 932 431 500
+
+
+ max.mustermann@musterlieferant.de
+
+
+
+ 99199
+ BAHNHOFSTRASSE 99
+ MUSTERHAUSEN
+ DE
+
+
+ DE123456789
+
+
+
+ 009420
+ 4304171000002
+ MUSTER-KUNDE GMBH
+
+ 40235
+ KUNDENWEG 88
+ DUESSELDORF
+ DE
+
+
+
+ B123456789
+
+
+ A456123
+ 130
+
+
+
+
+ 4304171088093
+ MUSTER-MARKT
+
+ 8211
+
+
+ 31157
+ HAUPTSTRASSE 44
+ SARSTEDT
+ DE
+
+
+
+
+ 20180805
+
+
+
+ L87654321012345
+
+
+
+ EUR
+
+ 009420
+ 4304171000002
+ MUSTER-KUNDE GMBH
+
+ 40235
+ KUNDENWEG 88
+ DUESSELDORF
+ DE
+
+
+
+ 61.07
+ VAT
+ 321.40
+ 326.50
+ -5.10
+ S
+ 19.00
+
+
+ 8.93
+ VAT
+ 127.59
+ 130.70
+ -3.11
+ S
+ 7.00
+
+
+
+ false
+
+ 2.00
+ 280.00
+ 5.60
+ Rechnungsrabatt 1
+
+ VAT
+ S
+ 19.00
+
+
+
+
+ false
+
+ 2.00
+ 130.70
+ 2.61
+ Rechnungsrabatt 1
+
+ VAT
+ S
+ 7.00
+
+
+
+
+ false
+
+ 280.00
+ 2.50
+ Rechnungsrabatt 2
+
+ VAT
+ S
+ 19.00
+
+
+
+
+ false
+
+ 130.70
+ 0.50
+ Rechnungsrabatt 2
+
+ VAT
+ S
+ 7.00
+
+
+
+ Transportkosten
+ 3.00
+
+ VAT
+ S
+ 19.00
+
+
+
+ Bei Zahlung innerhalb 14 Tagen gewähren wir 2,0% Skonto.
+
+ 14
+ 2.00
+
+
+
+ 457.20
+ 3.00
+ 11.21
+ 448.99
+ 70.00
+ 518.99
+ 0.00
+ 518.99
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 03f326a5..7346b012 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
org.mustangproject
core
- 2.16.1-SNAPSHOT pom
+ 2.16.2-SNAPSHOT pom
Mustang
diff --git a/validator/pom.xml b/validator/pom.xml
index d8820ab1..6c94fd9e 100644
--- a/validator/pom.xml
+++ b/validator/pom.xml
@@ -3,7 +3,7 @@
org.mustangproject
core
- 2.16.1-SNAPSHOT
+ 2.16.2-SNAPSHOT
4.0.0
org.mustangproject
@@ -11,7 +11,7 @@
Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung)
jar
- 2.16.1-SNAPSHOT
+ 2.16.2-SNAPSHOT
@@ -38,7 +38,7 @@
${project.groupId}
library
- 2.16.1-SNAPSHOT
+ 2.16.2-SNAPSHOT
org.dom4j
@@ -73,7 +73,7 @@
org.verapdf
validation-model-jakarta
- 1.26.1
+ 1.26.2