Merge branch 'mustang-master' into forked-master

This commit is contained in:
Sebastian Sieber
2024-11-05 14:44:07 +01:00
16 changed files with 1010 additions and 885 deletions

View File

@@ -3,8 +3,16 @@
2024- 2024-
- 435 use invoiceimporter as common technical basis also for zugferdimporter - 435 use invoiceimporter as common technical basis also for zugferdimporter
- also import delivery address - also import delivery address
- 527 - 527 metrics raises errors
- 517 read product GlobalID
- 380 Added test for input stream validation
- 518 corrently validate more XRechnung versions
- make document charges and allowances serializable - make document charges and allowances serializable
- 523
- 530
- 532 support validation warnings!
- 534 new signature
-
2.14.2 2.14.2

View File

@@ -214,4 +214,16 @@ public class XMLTools extends XMLWriter {
return IOUtils.toByteArray (fileinput); return IOUtils.toByteArray (fileinput);
} }
public static String trimOrNull(Node node) {
if (node != null) {
String textContent = node.getTextContent();
if (textContent != null) {
return textContent.trim();
}
}
return null;
}
} }

View File

@@ -334,7 +334,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
this.trans = trans; this.trans = trans;
this.calc = new TransactionCalculator(trans); this.calc = new TransactionCalculator(trans);
boolean hasDueDate = false; boolean hasDueDate = trans.getDueDate()!=null;
final SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); final SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
String exemptionReason = ""; String exemptionReason = "";
@@ -818,7 +818,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
} }
} }
if ((trans.getPaymentTerms() == null) && (getProfile() != Profiles.getByName("Minimum")) && ((paymentTermsDescription != null) || (trans.getTradeSettlement() != null) || (hasDueDate))) { if ((trans.getPaymentTerms() == null) && (getProfile() != Profiles.getByName("Minimum")) && ((paymentTermsDescription != null) || (trans.getTradeSettlement() != null) || (hasDueDate))) {
xml += "<ram:SpecifiedTradePaymentTerms>"; xml += "<ram:SpecifiedTradePaymentTerms>";
@@ -834,7 +833,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
} }
} }
if (hasDueDate && (trans.getDueDate() != null)) { if (trans.getDueDate() != null) {
xml += "<ram:DueDateDateTime>" // $NON-NLS-2$ xml += "<ram:DueDateDateTime>" // $NON-NLS-2$
+ DATE.udtFormat(trans.getDueDate()) + DATE.udtFormat(trans.getDueDate())
+ "</ram:DueDateDateTime>";// 20130704 + "</ram:DueDateDateTime>";// 20130704

View File

@@ -14,55 +14,19 @@ package org.mustangproject.ZUGFeRD;
* @author jstaerk * @author jstaerk
*/ */
import java.io.*; import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath; import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathFactory;
import org.apache.commons.io.IOUtils;
import org.apache.fop.util.XMLUtil;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
import org.mustangproject.*; import org.mustangproject.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.*;
public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter { public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter {
private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRDImporter.class); private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRDImporter.class);
@@ -753,7 +717,7 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter {
SchemedID globalId = new SchemedID() SchemedID globalId = new SchemedID()
.setScheme(node.getAttributes() .setScheme(node.getAttributes()
.getNamedItem("schemeID").getNodeValue()) .getNamedItem("schemeID").getNodeValue())
.setId(getNodeValue(node)); .setId(XMLTools.getNodeValue(node));
lineItem.getProduct().addGlobalID(globalId); lineItem.getProduct().addGlobalID(globalId);
} }
node = getNodeByName(nn.getChildNodes(), "SellerAssignedID"); node = getNodeByName(nn.getChildNodes(), "SellerAssignedID");

View File

@@ -79,24 +79,6 @@ public class ZUGFeRDInvoiceImporter {
setInputStream(pdfStream); setInputStream(pdfStream);
} }
private static String trimOrNull(Node node) {
if (node != null) {
String textContent = node.getTextContent();
if (textContent != null) {
return textContent.trim();
}
}
return null;
}
private static String convertStreamToString(java.io.InputStream is) {
try {
return IOUtils.toString(is, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void setPDFFilename(String pdfFilename) { public void setPDFFilename(String pdfFilename) {
try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) { try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) {
extractLowLevel(bis); extractLowLevel(bis);
@@ -151,7 +133,8 @@ public class ZUGFeRDInvoiceImporter {
} }
final InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata(); final InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata();
xmpString = convertStreamToString(XMP);
xmpString = new String(XMLTools.getBytesFromStream(XMP), StandardCharsets.UTF_8);
final PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles(); final PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles();
if (etn == null) { if (etn == null) {
@@ -330,7 +313,7 @@ public class ZUGFeRDInvoiceImporter {
BigDecimal expectedGrandTotal = null; BigDecimal expectedGrandTotal = null;
NodeList totalNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); NodeList totalNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (totalNodes.getLength() > 0) { if (totalNodes.getLength() > 0) {
expectedGrandTotal = new BigDecimal(trimOrNull(totalNodes.item(0))); expectedGrandTotal = new BigDecimal(XMLTools.trimOrNull(totalNodes.item(0)));
if (zpp instanceof CalculatedInvoice) { if (zpp instanceof CalculatedInvoice) {
// usually we would re-calculate the invoice to get expectedGrandTotal // usually we would re-calculate the invoice to get expectedGrandTotal
// however, for "minimal" invoices or other invoices without lines // however, for "minimal" invoices or other invoices without lines
@@ -342,7 +325,7 @@ public class ZUGFeRDInvoiceImporter {
xpr = xpath.compile("//*[local-name()=\"PrepaidAmount\"]"); xpr = xpath.compile("//*[local-name()=\"PrepaidAmount\"]");
NodeList prepaidNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); NodeList prepaidNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (prepaidNodes.getLength() > 0) { if (prepaidNodes.getLength() > 0) {
zpp.setTotalPrepaidAmount(new BigDecimal(trimOrNull(prepaidNodes.item(0)))); zpp.setTotalPrepaidAmount(new BigDecimal(XMLTools.trimOrNull(prepaidNodes.item(0))));
} }
Date issueDate = null; Date issueDate = null;
@@ -355,17 +338,17 @@ public class ZUGFeRDInvoiceImporter {
for (int documentChildIndex = 0; documentChildIndex < exchangedDocumentChilds.getLength(); documentChildIndex++) { for (int documentChildIndex = 0; documentChildIndex < exchangedDocumentChilds.getLength(); documentChildIndex++) {
Node item = exchangedDocumentChilds.item(documentChildIndex); Node item = exchangedDocumentChilds.item(documentChildIndex);
if ((item.getLocalName() != null) && (item.getLocalName().equals("ID"))) { if ((item.getLocalName() != null) && (item.getLocalName().equals("ID"))) {
number = trimOrNull(item); number = XMLTools.trimOrNull(item);
} }
if ((item.getLocalName() != null) && (item.getLocalName().equals("TypeCode"))) { if ((item.getLocalName() != null) && (item.getLocalName().equals("TypeCode"))) {
typeCode = trimOrNull(item); typeCode = XMLTools.trimOrNull(item);
} }
if ((item.getLocalName() != null) && (item.getLocalName().equals("IssueDateTime"))) { if ((item.getLocalName() != null) && (item.getLocalName().equals("IssueDateTime"))) {
NodeList issueDateTimeChilds = item.getChildNodes(); NodeList issueDateTimeChilds = item.getChildNodes();
for (int issueDateChildIndex = 0; issueDateChildIndex < issueDateTimeChilds.getLength(); issueDateChildIndex++) { for (int issueDateChildIndex = 0; issueDateChildIndex < issueDateTimeChilds.getLength(); issueDateChildIndex++) {
if ((issueDateTimeChilds.item(issueDateChildIndex).getLocalName() != null) if ((issueDateTimeChilds.item(issueDateChildIndex).getLocalName() != null)
&& (issueDateTimeChilds.item(issueDateChildIndex).getLocalName().equals("DateTimeString"))) { && (issueDateTimeChilds.item(issueDateChildIndex).getLocalName().equals("DateTimeString"))) {
issueDate = new SimpleDateFormat("yyyyMMdd").parse(trimOrNull(issueDateTimeChilds.item(issueDateChildIndex))); issueDate = new SimpleDateFormat("yyyyMMdd").parse(XMLTools.trimOrNull(issueDateTimeChilds.item(issueDateChildIndex)));
} }
} }
} }
@@ -375,6 +358,7 @@ public class ZUGFeRDInvoiceImporter {
if (rootNode.equals("Invoice")) { if (rootNode.equals("Invoice")) {
// UBL... // UBL...
number = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"ID\"]").trim(); number = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"ID\"]").trim();
typeCode = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"InvoiceTypeCode\"]").trim();
issueDate = new SimpleDateFormat("yyyy-MM-dd").parse(extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"IssueDate\"]").trim()); issueDate = new SimpleDateFormat("yyyy-MM-dd").parse(extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"IssueDate\"]").trim());
String dueDt = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"DueDate\"]").trim(); String dueDt = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"DueDate\"]").trim();
if (dueDt.length() > 0) { if (dueDt.length() > 0) {
@@ -402,7 +386,7 @@ public class ZUGFeRDInvoiceImporter {
for (int occurenceChildIndex = 0; occurenceChildIndex < occurenceChilds.getLength(); occurenceChildIndex++) { for (int occurenceChildIndex = 0; occurenceChildIndex < occurenceChilds.getLength(); occurenceChildIndex++) {
if ((occurenceChilds.item(occurenceChildIndex).getLocalName() != null) if ((occurenceChilds.item(occurenceChildIndex).getLocalName() != null)
&& (occurenceChilds.item(occurenceChildIndex).getLocalName().equals("DateTimeString"))) { && (occurenceChilds.item(occurenceChildIndex).getLocalName().equals("DateTimeString"))) {
deliveryDate = new SimpleDateFormat("yyyyMMdd").parse(trimOrNull(occurenceChilds.item(occurenceChildIndex))); deliveryDate = new SimpleDateFormat("yyyyMMdd").parse(XMLTools.trimOrNull(occurenceChilds.item(occurenceChildIndex)));
} }
} }
} }
@@ -414,7 +398,7 @@ public class ZUGFeRDInvoiceImporter {
for (int despatchAdviceChildIndex = 0; despatchAdviceChildIndex < despatchAdviceChilds.getLength(); despatchAdviceChildIndex++) { for (int despatchAdviceChildIndex = 0; despatchAdviceChildIndex < despatchAdviceChilds.getLength(); despatchAdviceChildIndex++) {
if (despatchAdviceChilds.item(despatchAdviceChildIndex).getLocalName() != null if (despatchAdviceChilds.item(despatchAdviceChildIndex).getLocalName() != null
&& despatchAdviceChilds.item(despatchAdviceChildIndex).getLocalName().equals("IssuerAssignedID")) { && despatchAdviceChilds.item(despatchAdviceChildIndex).getLocalName().equals("IssuerAssignedID")) {
despatchAdviceReferencedDocument = trimOrNull(despatchAdviceChilds.item(despatchAdviceChildIndex)); despatchAdviceReferencedDocument = XMLTools.trimOrNull(despatchAdviceChilds.item(despatchAdviceChildIndex));
} }
} }
} }
@@ -427,7 +411,7 @@ public class ZUGFeRDInvoiceImporter {
String buyerOrderIssuerAssignedID = null; String buyerOrderIssuerAssignedID = null;
String sellerOrderIssuerAssignedID = null; String sellerOrderIssuerAssignedID = null;
for (int i = 0; i < headerTradeAgreementNodes.getLength(); i++) { for (int i = 0; i < headerTradeAgreementNodes.getLength(); i++) {
// trimOrNull(nodes.item(i)))) { // XMLTools.trimOrNull(nodes.item(i)))) {
Node headerTradeAgreementNode = headerTradeAgreementNodes.item(i); Node headerTradeAgreementNode = headerTradeAgreementNodes.item(i);
NodeList headerTradeAgreementChilds = headerTradeAgreementNode.getChildNodes(); NodeList headerTradeAgreementChilds = headerTradeAgreementNode.getChildNodes();
for (int agreementChildIndex = 0; agreementChildIndex < headerTradeAgreementChilds.getLength(); agreementChildIndex++) { for (int agreementChildIndex = 0; agreementChildIndex < headerTradeAgreementChilds.getLength(); agreementChildIndex++) {
@@ -437,7 +421,7 @@ public class ZUGFeRDInvoiceImporter {
for (int buyerOrderChildIndex = 0; buyerOrderChildIndex < buyerOrderChilds.getLength(); buyerOrderChildIndex++) { for (int buyerOrderChildIndex = 0; buyerOrderChildIndex < buyerOrderChilds.getLength(); buyerOrderChildIndex++) {
if ((buyerOrderChilds.item(buyerOrderChildIndex).getLocalName() != null) if ((buyerOrderChilds.item(buyerOrderChildIndex).getLocalName() != null)
&& (buyerOrderChilds.item(buyerOrderChildIndex).getLocalName().equals("IssuerAssignedID"))) { && (buyerOrderChilds.item(buyerOrderChildIndex).getLocalName().equals("IssuerAssignedID"))) {
buyerOrderIssuerAssignedID = trimOrNull(buyerOrderChilds.item(buyerOrderChildIndex)); buyerOrderIssuerAssignedID = XMLTools.trimOrNull(buyerOrderChilds.item(buyerOrderChildIndex));
} }
} }
} }
@@ -447,7 +431,7 @@ public class ZUGFeRDInvoiceImporter {
for (int sellerOrderChildIndex = 0; sellerOrderChildIndex < sellerOrderChilds.getLength(); sellerOrderChildIndex++) { for (int sellerOrderChildIndex = 0; sellerOrderChildIndex < sellerOrderChilds.getLength(); sellerOrderChildIndex++) {
if ((sellerOrderChilds.item(sellerOrderChildIndex).getLocalName() != null) if ((sellerOrderChilds.item(sellerOrderChildIndex).getLocalName() != null)
&& (sellerOrderChilds.item(sellerOrderChildIndex).getLocalName().equals("IssuerAssignedID"))) { && (sellerOrderChilds.item(sellerOrderChildIndex).getLocalName().equals("IssuerAssignedID"))) {
sellerOrderIssuerAssignedID = trimOrNull(sellerOrderChilds.item(sellerOrderChildIndex)); sellerOrderIssuerAssignedID = XMLTools.trimOrNull(sellerOrderChilds.item(sellerOrderChildIndex));
} }
} }
} }
@@ -466,7 +450,7 @@ public class ZUGFeRDInvoiceImporter {
String IBAN = null, BIC = null; String IBAN = null, BIC = null;
for (int i = 0; i < headerTradeSettlementNodes.getLength(); i++) { for (int i = 0; i < headerTradeSettlementNodes.getLength(); i++) {
// trimOrNull(nodes.item(i)))) { // XMLTools.trimOrNull(nodes.item(i)))) {
Node headerTradeSettlementNode = headerTradeSettlementNodes.item(i); Node headerTradeSettlementNode = headerTradeSettlementNodes.item(i);
NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes(); NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes();
@@ -479,7 +463,7 @@ public class ZUGFeRDInvoiceImporter {
NodeList dueDateChilds = paymentTermChilds.item(paymentTermChildIndex).getChildNodes(); NodeList dueDateChilds = paymentTermChilds.item(paymentTermChildIndex).getChildNodes();
for (int dueDateChildIndex = 0; dueDateChildIndex < dueDateChilds.getLength(); dueDateChildIndex++) { for (int dueDateChildIndex = 0; dueDateChildIndex < dueDateChilds.getLength(); dueDateChildIndex++) {
if ((dueDateChilds.item(dueDateChildIndex).getLocalName() != null) && (dueDateChilds.item(dueDateChildIndex).getLocalName().equals("DateTimeString"))) { if ((dueDateChilds.item(dueDateChildIndex).getLocalName() != null) && (dueDateChilds.item(dueDateChildIndex).getLocalName().equals("DateTimeString"))) {
dueDate = new SimpleDateFormat("yyyyMMdd").parse(trimOrNull(dueDateChilds.item(dueDateChildIndex))); dueDate = new SimpleDateFormat("yyyyMMdd").parse(XMLTools.trimOrNull(dueDateChilds.item(dueDateChildIndex)));
} }
} }
} }
@@ -500,7 +484,7 @@ public class ZUGFeRDInvoiceImporter {
NodeList accountChilds = paymentMeansChilds.item(paymentMeansChildIndex).getChildNodes(); NodeList accountChilds = paymentMeansChilds.item(paymentMeansChildIndex).getChildNodes();
for (int accountChildIndex = 0; accountChildIndex < accountChilds.getLength(); accountChildIndex++) { for (int accountChildIndex = 0; accountChildIndex < accountChilds.getLength(); accountChildIndex++) {
if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds.item(accountChildIndex).getLocalName().equals("IBANID"))) {//CII if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds.item(accountChildIndex).getLocalName().equals("IBANID"))) {//CII
IBAN = trimOrNull(accountChilds.item(accountChildIndex)); IBAN = XMLTools.trimOrNull(accountChilds.item(accountChildIndex));
} }
} }
} }
@@ -508,7 +492,7 @@ public class ZUGFeRDInvoiceImporter {
NodeList accountChilds = paymentMeansChilds.item(paymentMeansChildIndex).getChildNodes(); NodeList accountChilds = paymentMeansChilds.item(paymentMeansChildIndex).getChildNodes();
for (int accountChildIndex = 0; accountChildIndex < accountChilds.getLength(); accountChildIndex++) { for (int accountChildIndex = 0; accountChildIndex < accountChilds.getLength(); accountChildIndex++) {
if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds.item(accountChildIndex).getLocalName().equals("BICID"))) {//CII if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds.item(accountChildIndex).getLocalName().equals("BICID"))) {//CII
BIC = trimOrNull(accountChilds.item(accountChildIndex)); BIC = XMLTools.trimOrNull(accountChilds.item(accountChildIndex));
} }
} }
} }
@@ -531,7 +515,7 @@ public class ZUGFeRDInvoiceImporter {
NodeList startPeriodChilds = periodChilds.item(periodChildIndex).getChildNodes(); NodeList startPeriodChilds = periodChilds.item(periodChildIndex).getChildNodes();
for (int startPeriodIndex = 0; startPeriodIndex < startPeriodChilds.getLength(); startPeriodIndex++) { for (int startPeriodIndex = 0; startPeriodIndex < startPeriodChilds.getLength(); startPeriodIndex++) {
if ((startPeriodChilds.item(startPeriodIndex).getLocalName() != null) && (startPeriodChilds.item(startPeriodIndex).getLocalName().equals("DateTimeString"))) {//CII if ((startPeriodChilds.item(startPeriodIndex).getLocalName() != null) && (startPeriodChilds.item(startPeriodIndex).getLocalName().equals("DateTimeString"))) {//CII
deliveryPeriodStart = trimOrNull(startPeriodChilds.item(startPeriodIndex)); deliveryPeriodStart = XMLTools.trimOrNull(startPeriodChilds.item(startPeriodIndex));
} }
} }
} }
@@ -539,7 +523,7 @@ public class ZUGFeRDInvoiceImporter {
NodeList endPeriodChilds = periodChilds.item(periodChildIndex).getChildNodes(); NodeList endPeriodChilds = periodChilds.item(periodChildIndex).getChildNodes();
for (int endPeriodIndex = 0; endPeriodIndex < endPeriodChilds.getLength(); endPeriodIndex++) { for (int endPeriodIndex = 0; endPeriodIndex < endPeriodChilds.getLength(); endPeriodIndex++) {
if ((endPeriodChilds.item(endPeriodIndex).getLocalName() != null) && (endPeriodChilds.item(endPeriodIndex).getLocalName().equals("DateTimeString"))) {//CII if ((endPeriodChilds.item(endPeriodIndex).getLocalName() != null) && (endPeriodChilds.item(endPeriodIndex).getLocalName().equals("DateTimeString"))) {//CII
deliveryPeriodEnd = trimOrNull(endPeriodChilds.item(endPeriodIndex)); deliveryPeriodEnd = XMLTools.trimOrNull(endPeriodChilds.item(endPeriodIndex));
} }
} }
} }
@@ -558,7 +542,7 @@ public class ZUGFeRDInvoiceImporter {
NodeList paymentMeansNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); NodeList paymentMeansNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < paymentMeansNodes.getLength(); i++) { for (int i = 0; i < paymentMeansNodes.getLength(); i++) {
// trimOrNull(nodes.item(i)))) { // XMLTools.trimOrNull(nodes.item(i)))) {
Node paymentMeansNode = paymentMeansNodes.item(i); Node paymentMeansNode = paymentMeansNodes.item(i);
NodeList paymentMeansChilds = paymentMeansNode.getChildNodes(); NodeList paymentMeansChilds = paymentMeansNode.getChildNodes();
for (int meansChildIndex = 0; meansChildIndex < paymentMeansChilds.getLength(); meansChildIndex++) { for (int meansChildIndex = 0; meansChildIndex < paymentMeansChilds.getLength(); meansChildIndex++) {
@@ -567,7 +551,7 @@ public class ZUGFeRDInvoiceImporter {
NodeList paymentTermChilds = paymentMeansChilds.item(meansChildIndex).getChildNodes(); NodeList paymentTermChilds = paymentMeansChilds.item(meansChildIndex).getChildNodes();
for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds.getLength(); paymentTermChildIndex++) { for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds.getLength(); paymentTermChildIndex++) {
if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("ID"))) { if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("ID"))) {
IBAN = trimOrNull(paymentTermChilds.item(paymentTermChildIndex)); IBAN = XMLTools.trimOrNull(paymentTermChilds.item(paymentTermChildIndex));
if (IBAN != null) { if (IBAN != null) {
BankDetails bd = new BankDetails(IBAN); BankDetails bd = new BankDetails(IBAN);
bankDetails.add(bd); bankDetails.add(bd);
@@ -607,7 +591,7 @@ public class ZUGFeRDInvoiceImporter {
String buyerReference = null; String buyerReference = null;
prepaidNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); prepaidNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (prepaidNodes.getLength() > 0) { if (prepaidNodes.getLength() > 0) {
buyerReference = trimOrNull(prepaidNodes.item(0)); buyerReference = XMLTools.trimOrNull(prepaidNodes.item(0));
} }
if (buyerReference != null) { if (buyerReference != null) {
zpp.setReferenceNumber(buyerReference); zpp.setReferenceNumber(buyerReference);
@@ -629,7 +613,7 @@ public class ZUGFeRDInvoiceImporter {
xpr = xpath.compile("//*[local-name()=\"AttachmentBinaryObject\"]|//*[local-name()=\"EmbeddedDocumentBinaryObject\"]"); xpr = xpath.compile("//*[local-name()=\"AttachmentBinaryObject\"]|//*[local-name()=\"EmbeddedDocumentBinaryObject\"]");
NodeList attachmentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); NodeList attachmentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < attachmentNodes.getLength(); i++) { 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(trimOrNull(attachmentNodes.item(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))));
fileAttachments.add(fa); fileAttachments.add(fa);
// filename = "Aufmass.png" mimeCode = "image/png" // filename = "Aufmass.png" mimeCode = "image/png"
//EmbeddedDocumentBinaryObject cbc:EmbeddedDocumentBinaryObject mimeCode="image/png" filename="Aufmass.png" //EmbeddedDocumentBinaryObject cbc:EmbeddedDocumentBinaryObject mimeCode="image/png" filename="Aufmass.png"
@@ -657,21 +641,21 @@ public class ZUGFeRDInvoiceImporter {
for (int indicatorChildIndex = 0; indicatorChildIndex < indicatorChilds.getLength(); indicatorChildIndex++) { for (int indicatorChildIndex = 0; indicatorChildIndex < indicatorChilds.getLength(); indicatorChildIndex++) {
if ((indicatorChilds.item(indicatorChildIndex).getLocalName() != null) if ((indicatorChilds.item(indicatorChildIndex).getLocalName() != null)
&& (indicatorChilds.item(indicatorChildIndex).getLocalName().equals("Indicator"))) { && (indicatorChilds.item(indicatorChildIndex).getLocalName().equals("Indicator"))) {
isCharge = trimOrNull(indicatorChilds.item(indicatorChildIndex)).equalsIgnoreCase("true"); isCharge = XMLTools.trimOrNull(indicatorChilds.item(indicatorChildIndex)).equalsIgnoreCase("true");
} }
} }
} else if (chargeChildName.equals("ActualAmount")) { } else if (chargeChildName.equals("ActualAmount")) {
chargeAmount = trimOrNull(chargeNodeChilds.item(chargeChildIndex)); chargeAmount = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
} else if (chargeChildName.equals("Reason")) { } else if (chargeChildName.equals("Reason")) {
reason = trimOrNull(chargeNodeChilds.item(chargeChildIndex)); reason = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
} else if (chargeChildName.equals("ReasonCode")) { } else if (chargeChildName.equals("ReasonCode")) {
reasonCode = trimOrNull(chargeNodeChilds.item(chargeChildIndex)); reasonCode = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
} else if (chargeChildName.equals("CategoryTradeTax")) { } else if (chargeChildName.equals("CategoryTradeTax")) {
NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes(); NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes();
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) { for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
String taxItemName = taxChilds.item(taxChildIndex).getLocalName(); String taxItemName = taxChilds.item(taxChildIndex).getLocalName();
if ((taxItemName != null) && (taxItemName.equals("RateApplicablePercent") || taxItemName.equals("ApplicablePercent"))) { if ((taxItemName != null) && (taxItemName.equals("RateApplicablePercent") || taxItemName.equals("ApplicablePercent"))) {
taxPercent = trimOrNull(taxChilds.item(taxChildIndex)); taxPercent = XMLTools.trimOrNull(taxChilds.item(taxChildIndex));
} }
} }
} }
@@ -721,7 +705,7 @@ public class ZUGFeRDInvoiceImporter {
&& ((!expectedStringTotalGross.equals(XMLTools.nDigitFormat(expectedGrandTotal, 2))) && ((!expectedStringTotalGross.equals(XMLTools.nDigitFormat(expectedGrandTotal, 2)))
&& (!ignoreCalculationErrors))) { && (!ignoreCalculationErrors))) {
throw new ParseException( throw new ParseException(
"Could not reproduce the invoice, this could mean that it could not be read properly exp "+expectedStringTotalGross+" is "+XMLTools.nDigitFormat(expectedGrandTotal, 2), 0); "Could not reproduce the invoice, this could mean that it could not be read properly", 0);
} }
} }
return zpp; return zpp;

View File

@@ -64,7 +64,7 @@
<x:xmpmeta xmlns:x="adobe:ns:meta/"> <x:xmpmeta xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/"> <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:title><xsl:value-of select="xr:Invoice_number"/></dc:title> <dc:title><rdf:Alt><rdf:li xml:lang="x-default"><xsl:value-of select="xr:Invoice_number"/></rdf:li></rdf:Alt></dc:title>
<!-- <!--
<dc:creator></dc:creator> <dc:creator></dc:creator>
<dc:description></dc:description> <dc:description></dc:description>

View File

@@ -130,5 +130,60 @@ public class DeSerializationTest extends TestCase {
public void testDueDateRoundtrip() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
// [{"stringValue":"a","intValue":1,"booleanValue":true},
// {"stringValue":"bc","intValue":3,"booleanValue":false}]
Invoice fromJSON = mapper.readValue("{\n" +
" \"number\": \"RE - 228\",\n" +
" \"currency\": \"EUR\",\n" +
" \"issueDate\": \"2024-10-24\",\n" +
" \"dueDate\": \"2024-10-26\",\n" +
" \"deliveryDate\": \"2024-10-25\",\n" +
" \"sender\": {\n" +
" \"name\": \"Amazing Company\",\n" +
" \"zip\": \"10000\",\n" +
" \"street\": \"Straße der Kosmonauten 20\",\n" +
" \"location\": \"Berlin\",\n" +
" \"country\": \"DE\",\n" +
" \"taxID\": \"201/113/40209\",\n" +
" \"vatID\": \"DE123456789\",\n" +
" \"globalID\": \"4000001123452\",\n" +
" \"globalIDScheme\": \"0088\"\n" +
" },\n" +
" \"recipient\": {\n" +
" \"name\": \"Amazing Company\",\n" +
" \"zip\": \"1000\",\n" +
" \"street\": \"Straße der Kosmonauten 10\",\n" +
" \"location\": \"Berlin\",\n" +
" \"taxID\": \"201/113/40209\",\n" +
" \"vatID\": \"DE123456789\",\n" +
" \"country\": \"DE\"\n" +
" },\n" +
" \"zfitems\": [\n" +
" {\n" +
" \"price\": 99.9,\n" +
" \"quantity\": 10,\n" +
" \"product\": {\n" +
" \"unit\": \"H87\",\n" +
" \"name\": \"Amazing Archives\",\n" +
" \"description\": \"123\",\n" +
" \"vatpercent\": \"19\",\n" +
" \"taxCategoryCode\": \"3\"\n" +
" }\n" +
" }\n" +
" ]\n" +
"}\n", Invoice.class);
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
zf2p.setProfile(Profiles.getByName("XRechnung"));
zf2p.generateXML(fromJSON);
String theXML = new String(zf2p.getXML());
assertTrue(theXML.contains("<udt:DateTimeString format=\"102\">20241026</udt:DateTimeString>"));
}
} }

View File

@@ -21,6 +21,7 @@
*/ */
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.mustangproject.*; import org.mustangproject.*;
@@ -351,34 +352,79 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
} }
public void testEEISI_300_cii_Import() {
public void testImportMinimum() {
File CIIinputFile = getResourceAsFile("cii/facturFrMinimum.xml");
try {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(CIIinputFile));
CalculatedInvoice i=new CalculatedInvoice();
zii.extractInto(i);
assertEquals("671.15", i.getGrandTotal().toString());
} catch (IOException e) {
fail("IOException not expected");
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public void testEEISI_300_cii_Import() throws XPathExpressionException, ParseException {
boolean hasExceptions = false; boolean hasExceptions = false;
/* File input = getResourceAsFile("not_validating_full_invoice_based_onTest_EeISI_300_CENfullmodel.cii.xml"); File inputCII = getResourceAsFile("not_validating_full_invoice_based_onTest_EeISI_300_CENfullmodel.cii.xml");
File inputUBL = getResourceAsFile("not_validating_full_invoice_based_onTest_EeISI_300_CENfullmodel.ubl.xml");
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(); ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
try { try {
zii.fromXML(new String(Files.readAllBytes(input.toPath()), StandardCharsets.UTF_8)); zii.fromXML(new String(Files.readAllBytes(inputCII.toPath()), StandardCharsets.UTF_8));
} catch (IOException e) { } catch (IOException e) {
hasExceptions = true; hasExceptions = true;
} }
Invoice invoice = null; Invoice invoiceUBL = null;
invoiceUBL = zii.extractInvoice();
try { try {
invoice = zii.extractInvoice(); zii.fromXML(new String(Files.readAllBytes(inputUBL.toPath()), StandardCharsets.UTF_8));
assertEquals("Seller contact point",invoice.getSender().getName());
} catch (IOException e) {
hasExceptions = true;
}
Invoice invoiceCII = null;
try {
invoiceCII = zii.extractInvoice();
ObjectMapper mapper = new ObjectMapper();
String ubl=mapper.writeValueAsString(invoiceUBL);
String cii=mapper.writeValueAsString(invoiceCII);
assertEquals(cii,ubl);
/* /*
<cbc:Name>Seller contact point</cbc:Name> <cbc:Name>Seller contact point</cbc:Name>
<cbc:Telephone>+41 345 654455</cbc:Telephone> <cbc:Telephone>+41 345 654455</cbc:Telephone>
<cbc:ElectronicMail>seller@contact.de);* <cbc:ElectronicMail>seller@contact.de);*/
} catch (XPathExpressionException | ParseException e) { } catch (XPathExpressionException | ParseException e) {
hasExceptions = true; hasExceptions = true;
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
} }
assertFalse(hasExceptions); assertFalse(hasExceptions);
TransactionCalculator tc = new TransactionCalculator(invoice);
TransactionCalculator tc = new TransactionCalculator(invoiceCII);
assertEquals(new BigDecimal("205.00"), tc.getGrandTotal()); assertEquals(new BigDecimal("205.00"), tc.getGrandTotal());
*/
} }

View File

@@ -0,0 +1,56 @@
<?xml version='1.0' encoding='UTF-8'?>
<rsm:CrossIndustryInvoice xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:factur-x.eu:1p0:minimum</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>FA-2017-0010</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20171113</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>Au bon moulin</ram:Name>
<ram:SpecifiedLegalOrganization>
<ram:ID schemeID="0002">99999999800010</ram:ID>
</ram:SpecifiedLegalOrganization>
<ram:PostalTradeAddress>
<ram:CountryID>FR</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">FR11999999998</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Ma jolie boutique</ram:Name>
<ram:SpecifiedLegalOrganization>
<ram:ID schemeID="0002">78787878400035</ram:ID>
</ram:SpecifiedLegalOrganization>
<ram:PostalTradeAddress>
<ram:CountryID>FR</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">FR19787878784</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
<ram:BuyerOrderReferencedDocument>
<ram:IssuerAssignedID>PO445</ram:IssuerAssignedID>
</ram:BuyerOrderReferencedDocument>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery/>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:TaxBasisTotalAmount currencyID="EUR">624.90</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">46.25</ram:TaxTotalAmount>
<ram:GrandTotalAmount currencyID="EUR">671.15</ram:GrandTotalAmount>
<ram:DuePayableAmount currencyID="EUR">470.15</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>

View File

@@ -98,7 +98,7 @@
<udt:Indicator>false</udt:Indicator> <udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator> </ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent> <ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount> <ram:BasisAmount>100.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount> <ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>95</ram:ReasonCode> <ram:ReasonCode>95</ram:ReasonCode>
<ram:Reason>Invoice line allowance reason</ram:Reason> <ram:Reason>Invoice line allowance reason</ram:Reason>
@@ -108,13 +108,13 @@
<udt:Indicator>true</udt:Indicator> <udt:Indicator>true</udt:Indicator>
</ram:ChargeIndicator> </ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent> <ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount> <ram:BasisAmount>100.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount> <ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>AAA</ram:ReasonCode> <ram:ReasonCode>AAA</ram:ReasonCode>
<ram:Reason>Invoice line charge reason</ram:Reason> <ram:Reason>Invoice line charge reason</ram:Reason>
</ram:SpecifiedTradeAllowanceCharge> </ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedTradeSettlementLineMonetarySummation> <ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>1000.00</ram:LineTotalAmount> <ram:LineTotalAmount>100.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation> </ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:AdditionalReferencedDocument> <ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>Line object identifier</ram:IssuerAssignedID> <ram:IssuerAssignedID>Line object identifier</ram:IssuerAssignedID>
@@ -147,7 +147,7 @@
<ram:RateApplicablePercent>0.00</ram:RateApplicablePercent> <ram:RateApplicablePercent>0.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax> </ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation> <ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>1000.00</ram:LineTotalAmount> <ram:LineTotalAmount>100.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation> </ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement> </ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem> </ram:IncludedSupplyChainTradeLineItem>
@@ -327,9 +327,9 @@
</ram:PayerSpecifiedDebtorFinancialInstitution> --> </ram:PayerSpecifiedDebtorFinancialInstitution> -->
</ram:SpecifiedTradeSettlementPaymentMeans> </ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax> <ram:ApplicableTradeTax>
<ram:CalculatedAmount>50.00</ram:CalculatedAmount> <ram:CalculatedAmount>5.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode> <ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>1000.00</ram:BasisAmount> <ram:BasisAmount>100.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode> <ram:CategoryCode>S</ram:CategoryCode>
<!-- <ram:DueDateTypeCode>29</ram:DueDateTypeCode> --> <!-- <ram:DueDateTypeCode>29</ram:DueDateTypeCode> -->
<ram:RateApplicablePercent>5.00</ram:RateApplicablePercent> <ram:RateApplicablePercent>5.00</ram:RateApplicablePercent>
@@ -338,7 +338,7 @@
<ram:CalculatedAmount>0.00</ram:CalculatedAmount> <ram:CalculatedAmount>0.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode> <ram:TypeCode>VAT</ram:TypeCode>
<ram:ExemptionReason>Exemtion reason text</ram:ExemptionReason> <ram:ExemptionReason>Exemtion reason text</ram:ExemptionReason>
<ram:BasisAmount>1000.00</ram:BasisAmount> <ram:BasisAmount>100.00</ram:BasisAmount>
<ram:CategoryCode>E</ram:CategoryCode> <ram:CategoryCode>E</ram:CategoryCode>
<ram:ExemptionReasonCode>VATEX-EU-O</ram:ExemptionReasonCode> <ram:ExemptionReasonCode>VATEX-EU-O</ram:ExemptionReasonCode>
<ram:DueDateTypeCode>29</ram:DueDateTypeCode> <ram:DueDateTypeCode>29</ram:DueDateTypeCode>
@@ -357,7 +357,7 @@
<udt:Indicator>false</udt:Indicator> <udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator> </ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent> <ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount> <ram:BasisAmount>100.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount> <ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>95</ram:ReasonCode> <ram:ReasonCode>95</ram:ReasonCode>
<ram:Reason>Doc allowance reason text</ram:Reason> <ram:Reason>Doc allowance reason text</ram:Reason>
@@ -372,7 +372,7 @@
<udt:Indicator>true</udt:Indicator> <udt:Indicator>true</udt:Indicator>
</ram:ChargeIndicator> </ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent> <ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount> <ram:BasisAmount>100.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount> <ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>AAA</ram:ReasonCode> <ram:ReasonCode>AAA</ram:ReasonCode>
<ram:Reason>Doc charge reason text</ram:Reason> <ram:Reason>Doc charge reason text</ram:Reason>
@@ -390,16 +390,16 @@
<ram:DirectDebitMandateID>Mandate reference identifier</ram:DirectDebitMandateID> <ram:DirectDebitMandateID>Mandate reference identifier</ram:DirectDebitMandateID>
</ram:SpecifiedTradePaymentTerms> </ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation> <ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>2000.00</ram:LineTotalAmount> <ram:LineTotalAmount>200.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>10.00</ram:ChargeTotalAmount> <ram:ChargeTotalAmount>10.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>10.00</ram:AllowanceTotalAmount> <ram:AllowanceTotalAmount>10.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>2000.00</ram:TaxBasisTotalAmount> <ram:TaxBasisTotalAmount>200.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">50.00</ram:TaxTotalAmount> <ram:TaxTotalAmount currencyID="EUR">5.00</ram:TaxTotalAmount>
<ram:TaxTotalAmount currencyID="NOK">46.00</ram:TaxTotalAmount> <ram:TaxTotalAmount currencyID="NOK">4.60</ram:TaxTotalAmount>
<ram:RoundingAmount>0.00</ram:RoundingAmount> <ram:RoundingAmount>0.00</ram:RoundingAmount>
<ram:GrandTotalAmount>2050.00</ram:GrandTotalAmount> <ram:GrandTotalAmount>205.00</ram:GrandTotalAmount>
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount> <ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
<ram:DuePayableAmount>2050.00</ram:DuePayableAmount> <ram:DuePayableAmount>205.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation> </ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:InvoiceReferencedDocument> <ram:InvoiceReferencedDocument>
<ram:IssuerAssignedID>abc123</ram:IssuerAssignedID> <ram:IssuerAssignedID>abc123</ram:IssuerAssignedID>

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ccts="urn:un:unece:uncefact:documentation:2" xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDataTypes-2" xmlns:udt="urn:oasis:names:specification:ubl:schema:xsd:UnqualifiedDataTypes-2"> <Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cec="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID> <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
<cbc:ProfileID>BT-23 Business Process Type</cbc:ProfileID> <cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>Test_EeISI_100</cbc:ID> <cbc:ID>Test_EeISI_100</cbc:ID>
<cbc:IssueDate>2018-11-12</cbc:IssueDate> <cbc:IssueDate>2018-11-12</cbc:IssueDate>
<cbc:DueDate>2018-11-30</cbc:DueDate> <cbc:DueDate>2018-11-30</cbc:DueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode> <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:Note>##AAA##invoice note text</cbc:Note> <cbc:Note>#AAA#invoice note text</cbc:Note>
<cbc:Note>##AAA##invoice note text 2</cbc:Note> <cbc:Note>#AAA#invoice note text 2</cbc:Note>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode> <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cbc:TaxCurrencyCode>NOK</cbc:TaxCurrencyCode> <cbc:TaxCurrencyCode>NOK</cbc:TaxCurrencyCode>
<cbc:AccountingCost>uvz</cbc:AccountingCost> <cbc:AccountingCost>uvz</cbc:AccountingCost>
@@ -15,7 +15,6 @@
<cac:InvoicePeriod> <cac:InvoicePeriod>
<cbc:StartDate>2018-11-12</cbc:StartDate> <cbc:StartDate>2018-11-12</cbc:StartDate>
<cbc:EndDate>2018-11-30</cbc:EndDate> <cbc:EndDate>2018-11-30</cbc:EndDate>
<cbc:DescriptionCode>35</cbc:DescriptionCode>
</cac:InvoicePeriod> </cac:InvoicePeriod>
<cac:OrderReference> <cac:OrderReference>
<cbc:ID>abc</cbc:ID> <cbc:ID>abc</cbc:ID>
@@ -33,16 +32,9 @@
<cac:ReceiptDocumentReference> <cac:ReceiptDocumentReference>
<cbc:ID>ghi</cbc:ID> <cbc:ID>ghi</cbc:ID>
</cac:ReceiptDocumentReference> </cac:ReceiptDocumentReference>
<cac:OriginatorDocumentReference>
<cbc:ID>opq</cbc:ID>
</cac:OriginatorDocumentReference>
<cac:ContractDocumentReference> <cac:ContractDocumentReference>
<cbc:ID>789</cbc:ID> <cbc:ID>789</cbc:ID>
</cac:ContractDocumentReference> </cac:ContractDocumentReference>
<cac:AdditionalDocumentReference>
<cbc:ID schemeID="0090">rst</cbc:ID>
<cbc:DocumentTypeCode>130</cbc:DocumentTypeCode>
</cac:AdditionalDocumentReference>
<cac:AdditionalDocumentReference> <cac:AdditionalDocumentReference>
<cbc:ID>Supporting document ref</cbc:ID> <cbc:ID>Supporting document ref</cbc:ID>
<cbc:DocumentDescription>Supporting document descr</cbc:DocumentDescription> <cbc:DocumentDescription>Supporting document descr</cbc:DocumentDescription>
@@ -53,21 +45,22 @@
</cac:ExternalReference> </cac:ExternalReference>
</cac:Attachment> </cac:Attachment>
</cac:AdditionalDocumentReference> </cac:AdditionalDocumentReference>
<cac:AdditionalDocumentReference>
<cbc:ID schemeID="AAA">rst</cbc:ID>
<cbc:DocumentTypeCode>130</cbc:DocumentTypeCode>
</cac:AdditionalDocumentReference>
<cac:ProjectReference> <cac:ProjectReference>
<cbc:ID>456</cbc:ID> <cbc:ID>456</cbc:ID>
</cac:ProjectReference> </cac:ProjectReference>
<cac:AccountingSupplierParty> <cac:AccountingSupplierParty>
<cac:Party> <cac:Party>
<cbc:EndpointID schemeID="SMTP">Seller electronic address</cbc:EndpointID> <cbc:EndpointID schemeID="EM">Seller electronic address</cbc:EndpointID>
<cac:PartyIdentification> <cac:PartyIdentification>
<cbc:ID schemeID="0100">Seller identifier 1</cbc:ID> <cbc:ID schemeID="0100">Seller identifier 1</cbc:ID>
</cac:PartyIdentification> </cac:PartyIdentification>
<cac:PartyIdentification> <cac:PartyIdentification>
<cbc:ID schemeID="0110">Seller identifier 2</cbc:ID> <cbc:ID schemeID="0110">Seller identifier 2</cbc:ID>
</cac:PartyIdentification> </cac:PartyIdentification>
<cac:PartyIdentification>
<cbc:ID schemeID="SEPA">Bank assigned creditor identifier</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName> <cac:PartyName>
<cbc:Name>Seller trading name</cbc:Name> <cbc:Name>Seller trading name</cbc:Name>
</cac:PartyName> </cac:PartyName>
@@ -93,12 +86,11 @@
<cac:PartyTaxScheme> <cac:PartyTaxScheme>
<cbc:CompanyID>DE49294093</cbc:CompanyID> <cbc:CompanyID>DE49294093</cbc:CompanyID>
<cac:TaxScheme> <cac:TaxScheme>
<cbc:ID>NOVAT</cbc:ID> <cbc:ID>FC</cbc:ID>
</cac:TaxScheme> </cac:TaxScheme>
</cac:PartyTaxScheme> </cac:PartyTaxScheme>
<cac:PartyLegalEntity> <cac:PartyLegalEntity>
<cbc:RegistrationName>Seller name</cbc:RegistrationName> <cbc:RegistrationName>Seller name</cbc:RegistrationName>
<cbc:CompanyID schemeID="0310">Seller legal identifier</cbc:CompanyID>
<cbc:CompanyLegalForm>Seller additional legal information</cbc:CompanyLegalForm> <cbc:CompanyLegalForm>Seller additional legal information</cbc:CompanyLegalForm>
</cac:PartyLegalEntity> </cac:PartyLegalEntity>
<cac:Contact> <cac:Contact>
@@ -110,9 +102,9 @@
</cac:AccountingSupplierParty> </cac:AccountingSupplierParty>
<cac:AccountingCustomerParty> <cac:AccountingCustomerParty>
<cac:Party> <cac:Party>
<cbc:EndpointID schemeID="DE:SMTP">Buyer electronic address</cbc:EndpointID> <cbc:EndpointID schemeID="EM">Buyer electronic address</cbc:EndpointID>
<cac:PartyIdentification> <cac:PartyIdentification>
<cbc:ID>0190:Buyer identifier</cbc:ID> <cbc:ID schemeID="0190">Buyer identifier</cbc:ID>
</cac:PartyIdentification> </cac:PartyIdentification>
<cac:PartyName> <cac:PartyName>
<cbc:Name>Buyer trading name</cbc:Name> <cbc:Name>Buyer trading name</cbc:Name>
@@ -138,7 +130,7 @@
</cac:PartyTaxScheme> </cac:PartyTaxScheme>
<cac:PartyLegalEntity> <cac:PartyLegalEntity>
<cbc:RegistrationName>Buyer name</cbc:RegistrationName> <cbc:RegistrationName>Buyer name</cbc:RegistrationName>
<cbc:CompanyID>Buyer legal registration identifier</cbc:CompanyID> <cbc:CompanyID schemeID="0089">Buyer legal registration identifier</cbc:CompanyID>
</cac:PartyLegalEntity> </cac:PartyLegalEntity>
<cac:Contact> <cac:Contact>
<cbc:Name>Buyer contact point</cbc:Name> <cbc:Name>Buyer contact point</cbc:Name>
@@ -154,9 +146,6 @@
<cac:PartyName> <cac:PartyName>
<cbc:Name>Payee name</cbc:Name> <cbc:Name>Payee name</cbc:Name>
</cac:PartyName> </cac:PartyName>
<cac:PartyLegalEntity>
<cbc:CompanyID schemeID="0099">Payee legal registration identifier</cbc:CompanyID>
</cac:PartyLegalEntity>
</cac:PayeeParty> </cac:PayeeParty>
<cac:TaxRepresentativeParty> <cac:TaxRepresentativeParty>
<cac:PartyName> <cac:PartyName>
@@ -206,48 +195,19 @@
</cac:PartyName> </cac:PartyName>
</cac:DeliveryParty> </cac:DeliveryParty>
</cac:Delivery> </cac:Delivery>
<cac:PaymentMeans>
<cbc:PaymentMeansCode name="SEPA">4</cbc:PaymentMeansCode>
<cbc:PaymentID>Remittance information</cbc:PaymentID>
<cac:CardAccount>
<cbc:PrimaryAccountNumberID>1234</cbc:PrimaryAccountNumberID>
<cbc:NetworkID>mandatory network id</cbc:NetworkID>
<cbc:HolderName>Payment card holder name</cbc:HolderName>
</cac:CardAccount>
<cac:PayeeFinancialAccount>
<cbc:ID>IT1212341234123412</cbc:ID>
<cbc:Name>Payment account name</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>BSCTCH22</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
<cac:PayeeFinancialAccount>
<cbc:ID>IT1212341234123413</cbc:ID>
<cbc:Name>Payment account name 2</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>BSCTCH22</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
<cac:PaymentMandate>
<cbc:ID>Mandate reference identifier</cbc:ID>
<cac:PayerFinancialAccount>
<cbc:ID>Debited account identifier</cbc:ID>
</cac:PayerFinancialAccount>
</cac:PaymentMandate>
</cac:PaymentMeans>
<cac:PaymentTerms> <cac:PaymentTerms>
<cbc:Note>total amount</cbc:Note> <cbc:Note>total amount</cbc:Note>
</cac:PaymentTerms> </cac:PaymentTerms>
<cac:AllowanceCharge> <cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator> <cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>55</cbc:AllowanceChargeReasonCode> <cbc:AllowanceChargeReasonCode>95</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Doc allowance reason text</cbc:AllowanceChargeReason> <cbc:AllowanceChargeReason>Doc allowance reason text</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1.0000</cbc:MultiplierFactorNumeric> <cbc:MultiplierFactorNumeric>1.00</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10.00</cbc:Amount> <cbc:Amount currencyID="EUR">10</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000.00</cbc:BaseAmount> <cbc:BaseAmount currencyID="EUR">1000</cbc:BaseAmount>
<cac:TaxCategory> <cac:TaxCategory>
<cbc:ID>S</cbc:ID> <cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent> <cbc:Percent>5</cbc:Percent>
<cac:TaxScheme> <cac:TaxScheme>
<cbc:ID>VAT</cbc:ID> <cbc:ID>VAT</cbc:ID>
</cac:TaxScheme> </cac:TaxScheme>
@@ -257,40 +217,37 @@
<cbc:ChargeIndicator>true</cbc:ChargeIndicator> <cbc:ChargeIndicator>true</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>AAA</cbc:AllowanceChargeReasonCode> <cbc:AllowanceChargeReasonCode>AAA</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Doc charge reason text</cbc:AllowanceChargeReason> <cbc:AllowanceChargeReason>Doc charge reason text</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1.0000</cbc:MultiplierFactorNumeric> <cbc:MultiplierFactorNumeric>1.00</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10.00</cbc:Amount> <cbc:Amount currencyID="EUR">10</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000.00</cbc:BaseAmount> <cbc:BaseAmount currencyID="EUR">1000</cbc:BaseAmount>
<cac:TaxCategory> <cac:TaxCategory>
<cbc:ID>S</cbc:ID> <cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent> <cbc:Percent>5</cbc:Percent>
<cac:TaxScheme> <cac:TaxScheme>
<cbc:ID>VAT</cbc:ID> <cbc:ID>VAT</cbc:ID>
</cac:TaxScheme> </cac:TaxScheme>
</cac:TaxCategory> </cac:TaxCategory>
</cac:AllowanceCharge> </cac:AllowanceCharge>
<cac:TaxTotal> <cac:TaxTotal>
<cbc:TaxAmount currencyID="NOK">46.00</cbc:TaxAmount> <cbc:TaxAmount currencyID="EUR">50</cbc:TaxAmount>
</cac:TaxTotal>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">50.00</cbc:TaxAmount>
<cac:TaxSubtotal> <cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount> <cbc:TaxableAmount currencyID="EUR">1000</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">50.00</cbc:TaxAmount> <cbc:TaxAmount currencyID="EUR">50</cbc:TaxAmount>
<cac:TaxCategory> <cac:TaxCategory>
<cbc:ID>S</cbc:ID> <cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent> <cbc:Percent>5</cbc:Percent>
<cac:TaxScheme> <cac:TaxScheme>
<cbc:ID>VAT</cbc:ID> <cbc:ID>VAT</cbc:ID>
</cac:TaxScheme> </cac:TaxScheme>
</cac:TaxCategory> </cac:TaxCategory>
</cac:TaxSubtotal> </cac:TaxSubtotal>
<cac:TaxSubtotal> <cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount> <cbc:TaxableAmount currencyID="EUR">1000</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">0.00</cbc:TaxAmount> <cbc:TaxAmount currencyID="EUR">0</cbc:TaxAmount>
<cac:TaxCategory> <cac:TaxCategory>
<cbc:ID>E</cbc:ID> <cbc:ID>E</cbc:ID>
<cbc:Percent>0.00</cbc:Percent> <cbc:Percent>0</cbc:Percent>
<cbc:TaxExemptionReasonCode>Exemption reason code</cbc:TaxExemptionReasonCode> <cbc:TaxExemptionReasonCode>VATEX-EU-O</cbc:TaxExemptionReasonCode>
<cbc:TaxExemptionReason>Exemtion reason text</cbc:TaxExemptionReason> <cbc:TaxExemptionReason>Exemtion reason text</cbc:TaxExemptionReason>
<cac:TaxScheme> <cac:TaxScheme>
<cbc:ID>VAT</cbc:ID> <cbc:ID>VAT</cbc:ID>
@@ -298,19 +255,23 @@
</cac:TaxCategory> </cac:TaxCategory>
</cac:TaxSubtotal> </cac:TaxSubtotal>
</cac:TaxTotal> </cac:TaxTotal>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="NOK">46</cbc:TaxAmount>
</cac:TaxTotal>
<cac:LegalMonetaryTotal> <cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">2000.00</cbc:LineExtensionAmount> <cbc:LineExtensionAmount currencyID="EUR">200</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">2000.00</cbc:TaxExclusiveAmount> <cbc:TaxExclusiveAmount currencyID="EUR">200</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">2050.00</cbc:TaxInclusiveAmount> <cbc:TaxInclusiveAmount currencyID="EUR">205</cbc:TaxInclusiveAmount>
<cbc:AllowanceTotalAmount currencyID="EUR">10.00</cbc:AllowanceTotalAmount> <cbc:AllowanceTotalAmount currencyID="EUR">10</cbc:AllowanceTotalAmount>
<cbc:ChargeTotalAmount currencyID="EUR">10.00</cbc:ChargeTotalAmount> <cbc:ChargeTotalAmount currencyID="EUR">10</cbc:ChargeTotalAmount>
<cbc:PayableAmount currencyID="EUR">2050.00</cbc:PayableAmount> <cbc:PrepaidAmount currencyID="EUR">0</cbc:PrepaidAmount>
<cbc:PayableAmount currencyID="EUR">205</cbc:PayableAmount>
</cac:LegalMonetaryTotal> </cac:LegalMonetaryTotal>
<cac:InvoiceLine> <cac:InvoiceLine>
<cbc:ID>1a</cbc:ID> <cbc:ID>1a</cbc:ID>
<cbc:Note>Invoice line note</cbc:Note> <cbc:Note>Invoice line note</cbc:Note>
<cbc:InvoicedQuantity unitCode="EA">10.00000000</cbc:InvoicedQuantity> <cbc:InvoicedQuantity unitCode="EA">10</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount> <cbc:LineExtensionAmount currencyID="EUR">1000</cbc:LineExtensionAmount>
<cbc:AccountingCost>6789</cbc:AccountingCost> <cbc:AccountingCost>6789</cbc:AccountingCost>
<cac:InvoicePeriod> <cac:InvoicePeriod>
<cbc:StartDate>2018-11-12</cbc:StartDate> <cbc:StartDate>2018-11-12</cbc:StartDate>
@@ -320,14 +281,14 @@
<cbc:LineID>12345</cbc:LineID> <cbc:LineID>12345</cbc:LineID>
</cac:OrderLineReference> </cac:OrderLineReference>
<cac:DocumentReference> <cac:DocumentReference>
<cbc:ID schemeID="ZZZ">Line object identifier</cbc:ID> <cbc:ID>Line object identifier</cbc:ID>
<cbc:DocumentTypeCode>130</cbc:DocumentTypeCode> <cbc:DocumentTypeCode>130</cbc:DocumentTypeCode>
</cac:DocumentReference> </cac:DocumentReference>
<cac:AllowanceCharge> <cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator> <cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>55</cbc:AllowanceChargeReasonCode> <cbc:AllowanceChargeReasonCode>95</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Invoice line allowance reason</cbc:AllowanceChargeReason> <cbc:AllowanceChargeReason>Invoice line allowance reason</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1</cbc:MultiplierFactorNumeric> <cbc:MultiplierFactorNumeric>1.00</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10</cbc:Amount> <cbc:Amount currencyID="EUR">10</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000</cbc:BaseAmount> <cbc:BaseAmount currencyID="EUR">1000</cbc:BaseAmount>
</cac:AllowanceCharge> </cac:AllowanceCharge>
@@ -335,7 +296,7 @@
<cbc:ChargeIndicator>true</cbc:ChargeIndicator> <cbc:ChargeIndicator>true</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>AAA</cbc:AllowanceChargeReasonCode> <cbc:AllowanceChargeReasonCode>AAA</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Invoice line charge reason</cbc:AllowanceChargeReason> <cbc:AllowanceChargeReason>Invoice line charge reason</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1</cbc:MultiplierFactorNumeric> <cbc:MultiplierFactorNumeric>1.00</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10</cbc:Amount> <cbc:Amount currencyID="EUR">10</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000</cbc:BaseAmount> <cbc:BaseAmount currencyID="EUR">1000</cbc:BaseAmount>
</cac:AllowanceCharge> </cac:AllowanceCharge>
@@ -349,7 +310,7 @@
<cbc:ID>Item seller's identifier</cbc:ID> <cbc:ID>Item seller's identifier</cbc:ID>
</cac:SellersItemIdentification> </cac:SellersItemIdentification>
<cac:StandardItemIdentification> <cac:StandardItemIdentification>
<cbc:ID>Item standar identifier</cbc:ID> <cbc:ID schemeID="0060">Item standar identifier</cbc:ID>
</cac:StandardItemIdentification> </cac:StandardItemIdentification>
<cac:OriginCountry> <cac:OriginCountry>
<cbc:IdentificationCode>IT</cbc:IdentificationCode> <cbc:IdentificationCode>IT</cbc:IdentificationCode>
@@ -359,7 +320,7 @@
</cac:CommodityClassification> </cac:CommodityClassification>
<cac:ClassifiedTaxCategory> <cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID> <cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent> <cbc:Percent>5</cbc:Percent>
<cac:TaxScheme> <cac:TaxScheme>
<cbc:ID>VAT</cbc:ID> <cbc:ID>VAT</cbc:ID>
</cac:TaxScheme> </cac:TaxScheme>
@@ -374,8 +335,8 @@
</cac:AdditionalItemProperty> </cac:AdditionalItemProperty>
</cac:Item> </cac:Item>
<cac:Price> <cac:Price>
<cbc:PriceAmount currencyID="EUR">10.00</cbc:PriceAmount> <cbc:PriceAmount currencyID="EUR">10</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="EA">1.00</cbc:BaseQuantity> <cbc:BaseQuantity unitCode="EA">1</cbc:BaseQuantity>
<cac:AllowanceCharge> <cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator> <cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:Amount currencyID="EUR">1</cbc:Amount> <cbc:Amount currencyID="EUR">1</cbc:Amount>
@@ -385,20 +346,20 @@
</cac:InvoiceLine> </cac:InvoiceLine>
<cac:InvoiceLine> <cac:InvoiceLine>
<cbc:ID>1b</cbc:ID> <cbc:ID>1b</cbc:ID>
<cbc:InvoicedQuantity unitCode="EA">10.00000000</cbc:InvoicedQuantity> <cbc:InvoicedQuantity unitCode="EA">10</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount> <cbc:LineExtensionAmount currencyID="EUR">1000</cbc:LineExtensionAmount>
<cac:Item> <cac:Item>
<cbc:Name>Item name 2</cbc:Name> <cbc:Name>Item name 2</cbc:Name>
<cac:ClassifiedTaxCategory> <cac:ClassifiedTaxCategory>
<cbc:ID>E</cbc:ID> <cbc:ID>E</cbc:ID>
<cbc:Percent>0.00</cbc:Percent> <cbc:Percent>0</cbc:Percent>
<cac:TaxScheme> <cac:TaxScheme>
<cbc:ID>VAT</cbc:ID> <cbc:ID>VAT</cbc:ID>
</cac:TaxScheme> </cac:TaxScheme>
</cac:ClassifiedTaxCategory> </cac:ClassifiedTaxCategory>
</cac:Item> </cac:Item>
<cac:Price> <cac:Price>
<cbc:PriceAmount currencyID="EUR">10.00</cbc:PriceAmount> <cbc:PriceAmount currencyID="EUR">10</cbc:PriceAmount>
</cac:Price> </cac:Price>
</cac:InvoiceLine> </cac:InvoiceLine>
</Invoice> </Invoice>

View File

@@ -52,7 +52,7 @@ public class PDFValidator extends Validator {
} }
private static final Logger LOGGER = LoggerFactory.getLogger(PDFValidator.class.getCanonicalName()); // log output private static final Logger LOGGER = LoggerFactory.getLogger(PDFValidator.class.getCanonicalName()); // log output
private static final PDFAFlavour[] PDF_A_3_FLAVOURS = {PDFAFlavour.PDFA_3_A, PDFAFlavour.PDFA_3_A, PDFAFlavour.PDFA_3_A}; private static final PDFAFlavour[] PDF_A_3_FLAVOURS = {PDFAFlavour.PDFA_3_A, PDFAFlavour.PDFA_3_B, PDFAFlavour.PDFA_3_U};
private String pdfFilename; private String pdfFilename;
@@ -264,6 +264,7 @@ public class PDFValidator extends Validator {
final byte[] konikSignature = "Konik".getBytes(StandardCharsets.UTF_8); final byte[] konikSignature = "Konik".getBytes(StandardCharsets.UTF_8);
final byte[] pdfMachineSignature = "pdfMachine from Broadgun Software".getBytes(StandardCharsets.UTF_8); final byte[] pdfMachineSignature = "pdfMachine from Broadgun Software".getBytes(StandardCharsets.UTF_8);
final byte[] ghostscriptSignature = "%%Invocation:".getBytes(StandardCharsets.UTF_8); final byte[] ghostscriptSignature = "%%Invocation:".getBytes(StandardCharsets.UTF_8);
final byte[] cibpdfbrewerSignature = "CIB pdf brewer".getBytes(StandardCharsets.UTF_8);
if (ByteArraySearcher.contains(fileContents, symtraxSignature)) { if (ByteArraySearcher.contains(fileContents, symtraxSignature)) {
Signature = "Symtrax"; Signature = "Symtrax";
@@ -279,6 +280,8 @@ public class PDFValidator extends Validator {
Signature = "pdfMachine"; Signature = "pdfMachine";
} else if (ByteArraySearcher.contains(fileContents, ghostscriptSignature)) { } else if (ByteArraySearcher.contains(fileContents, ghostscriptSignature)) {
Signature = "Ghostscript"; Signature = "Ghostscript";
} else if (ByteArraySearcher.contains(fileContents, cibpdfbrewerSignature)) {
Signature = "CIB pdf brewer";
} }
context.setSignature(Signature); context.setSignature(Signature);
@@ -298,8 +301,10 @@ public class PDFValidator extends Validator {
if (!processorResult.getValidationResult().isCompliant()) { if (!processorResult.getValidationResult().isCompliant()) {
context.setInvalid(); context.setInvalid();
} }
PDFAFlavour pdfaFlavourFromValidationResult = processorResult.getValidationResult().getPDFAFlavour();
if (Arrays.stream(PDF_A_3_FLAVOURS) if (Arrays.stream(PDF_A_3_FLAVOURS)
.anyMatch(pdfaFlavour -> processorResult.getValidationResult().getPDFAFlavour().equals(pdfaFlavour))) { .noneMatch(pdfaFlavourFromValidationResult::equals)) {
context.addResultItem( context.addResultItem(
new ValidationResultItem(ESeverity.error, "Not a PDF/A-3").setSection(23).setPart(EPart.pdf)); new ValidationResultItem(ESeverity.error, "Not a PDF/A-3").setSection(23).setPart(EPart.pdf));

View File

@@ -419,11 +419,16 @@ public class XMLValidator extends Validator {
* @param xml the xml to be checked * @param xml the xml to be checked
* @param xsltFilename the filename of the intermediate XSLT file * @param xsltFilename the filename of the intermediate XSLT file
* @param section the error type code, if one arises * @param section the error type code, if one arises
* @param severity how serious a error should be treated - may only be notice * @param defaultSeverity how serious a error should be treated - may only be notice
* @throws IrrecoverableValidationError if anything happened that prevents further checks * @throws IrrecoverableValidationError if anything happened that prevents further checks
*/ */
public void validateSchematron(String xml, String xsltFilename, int section, ESeverity severity) throws IrrecoverableValidationError { public void validateSchematron(String xml, String xsltFilename, int section, ESeverity defaultSeverity) throws IrrecoverableValidationError {
ISchematronResource aResSCH = null; ISchematronResource aResSCH = null;
ESeverity severity=defaultSeverity;
if (defaultSeverity!=ESeverity.notice) {
severity=ESeverity.error;
}
aResSCH = SchematronResourceXSLT.fromClassPath(xsltFilename); aResSCH = SchematronResourceXSLT.fromClassPath(xsltFilename);
if (aResSCH != null) { if (aResSCH != null) {
@@ -465,6 +470,16 @@ public class XMLValidator extends Validator {
thisFailLocation = currentFailNode.getAttributes().getNamedItem("location").getNodeValue(); thisFailLocation = currentFailNode.getAttributes().getNamedItem("location").getNodeValue();
} }
if (currentFailNode.getAttributes().getNamedItem("flag") != null) {
// the XR issues warnings with flag=warning
if (currentFailNode.getAttributes().getNamedItem("flag").getNodeValue().equals("warning")) {
if (defaultSeverity!=ESeverity.notice) {
severity=ESeverity.warning;
}
}
}
NodeList failChilds = currentFailNode.getChildNodes(); NodeList failChilds = currentFailNode.getChildNodes();
for (int failChildIndex = 0; failChildIndex < failChilds.getLength(); failChildIndex++) { for (int failChildIndex = 0; failChildIndex < failChilds.getLength(); failChildIndex++) {
if (failChilds.item(failChildIndex).getLocalName() != null) { if (failChilds.item(failChildIndex).getLocalName() != null) {

View File

@@ -2,6 +2,15 @@ package org.mustangproject.validator;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.xmlunit.builder.Input;
import org.xmlunit.xpath.JAXPXPathEngine;
import org.xmlunit.xpath.XPathEngine;
import static org.xmlunit.assertj.XmlAssert.assertThat; import static org.xmlunit.assertj.XmlAssert.assertThat;
@@ -132,6 +141,17 @@ public class ZUGFeRDValidatorTest extends ResourceCase {
} }
public void testPDFA3AValidation() {
File tempFile = getResourceAsFile("zugferd_2p1_EXTENDED_PDFA-3A.pdf");
ZUGFeRDValidator zfv = new ZUGFeRDValidator();
String res = zfv.validate(tempFile.getAbsolutePath());
assertThat(res).valueByXPath("/validation/pdf/summary/@status")
.isEqualTo("valid");
}
/*** /***
* the XMLValidatorTests only cover the <xml></xml> part, this one includes the root element and * the XMLValidatorTests only cover the <xml></xml> part, this one includes the root element and
* the global <summary></summary> part as well * the global <summary></summary> part as well
@@ -205,6 +225,9 @@ public class ZUGFeRDValidatorTest extends ResourceCase {
assertThat(res).valueByXPath("count(//error)") assertThat(res).valueByXPath("count(//error)")
.asInt() .asInt()
.isEqualTo(3); .isEqualTo(3);
assertThat(res).valueByXPath("count(//warning)")
.asInt()
.isEqualTo(1);
assertThat(res).valueByXPath("count(//notice)") assertThat(res).valueByXPath("count(//notice)")
.asInt() .asInt()

View File

@@ -115,9 +115,6 @@
<ram:CityName>[Seller city]</ram:CityName> <ram:CityName>[Seller city]</ram:CityName>
<ram:CountryID>DE</ram:CountryID> <ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress> </ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID schemeID="EM">seller@email.de</ram:URIID>
</ram:URIUniversalCommunication>
<ram:SpecifiedTaxRegistration> <ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE 123456789</ram:ID> <ram:ID schemeID="VA">DE 123456789</ram:ID>
</ram:SpecifiedTaxRegistration> </ram:SpecifiedTaxRegistration>