Parsing exceptions of date strings does not break the whole XML parsing and sets the unparsable dates to null
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import javax.xml.XMLConstants;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.pdfbox.Loader;
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
@@ -9,8 +8,21 @@ import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
|||||||
import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
|
import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
||||||
import org.mustangproject.*;
|
import org.mustangproject.Allowance;
|
||||||
|
import org.mustangproject.BankDetails;
|
||||||
|
import org.mustangproject.CalculatedInvoice;
|
||||||
|
import org.mustangproject.Charge;
|
||||||
|
import org.mustangproject.DirectDebit;
|
||||||
|
import org.mustangproject.EStandard;
|
||||||
import org.mustangproject.Exceptions.StructureException;
|
import org.mustangproject.Exceptions.StructureException;
|
||||||
|
import org.mustangproject.FileAttachment;
|
||||||
|
import org.mustangproject.IncludedNote;
|
||||||
|
import org.mustangproject.Invoice;
|
||||||
|
import org.mustangproject.Item;
|
||||||
|
import org.mustangproject.ReferencedDocument;
|
||||||
|
import org.mustangproject.SchemedID;
|
||||||
|
import org.mustangproject.TradeParty;
|
||||||
|
import org.mustangproject.XMLTools;
|
||||||
import org.mustangproject.util.NodeMap;
|
import org.mustangproject.util.NodeMap;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -19,11 +31,19 @@ import org.w3c.dom.Node;
|
|||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.xpath.*;
|
import javax.xml.xpath.XPath;
|
||||||
import java.io.*;
|
import javax.xml.xpath.XPathConstants;
|
||||||
|
import javax.xml.xpath.XPathExpression;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -31,7 +51,16 @@ import java.nio.file.Paths;
|
|||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@@ -127,7 +156,7 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
if (Arrays.equals(pad, pdfSignature)) { // we have a pdf
|
if (Arrays.equals(pad, pdfSignature)) { // we have a pdf
|
||||||
|
|
||||||
|
|
||||||
try(PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(pdfStream))) {
|
try (PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(pdfStream))) {
|
||||||
// PDDocumentInformation info = doc.getDocumentInformation();
|
// PDDocumentInformation info = doc.getDocumentInformation();
|
||||||
final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
|
final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
|
||||||
//start
|
//start
|
||||||
@@ -175,7 +204,7 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
containsMeta = true;
|
containsMeta = true;
|
||||||
try {
|
try {
|
||||||
setRawXML(XMLTools.getBytesFromStream(pdfStream));
|
setRawXML(XMLTools.getBytesFromStream(pdfStream));
|
||||||
} catch(ParseException e) {
|
} catch (ParseException e) {
|
||||||
LOGGER.error("Failed to parse PDF", e);
|
LOGGER.error("Failed to parse PDF", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,19 +238,20 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
public boolean hasXMLFileAttachment() {
|
public boolean hasXMLFileAttachment() {
|
||||||
return containsAXMLFileAttachment;
|
return containsAXMLFileAttachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* sets th pdf attachments, and if a file is recognized (e.g. a factur-x.xml) triggers processing
|
* sets th pdf attachments, and if a file is recognized (e.g. a factur-x.xml) triggers processing
|
||||||
* @param names the Hashmap of String, PDComplexFileSpecification
|
* @param names the Hashmap of String, PDComplexFileSpecification
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void extractFiles(Map<String, PDComplexFileSpecification> names) throws IOException {
|
private void extractFiles(Map<String, PDComplexFileSpecification> names) throws IOException {
|
||||||
containsAXMLFileAttachment=false;
|
containsAXMLFileAttachment = false;
|
||||||
for (final String alias : names.keySet()) {
|
for (final String alias : names.keySet()) {
|
||||||
|
|
||||||
final PDComplexFileSpecification fileSpec = names.get(alias);
|
final PDComplexFileSpecification fileSpec = names.get(alias);
|
||||||
final String filename = fileSpec.getFilename();
|
final String filename = fileSpec.getFilename();
|
||||||
if (filename.toUpperCase().endsWith(".XML")) {
|
if (filename.toUpperCase().endsWith(".XML")) {
|
||||||
containsAXMLFileAttachment=true;
|
containsAXMLFileAttachment = true;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* filenames for invoice data (ZUGFeRD v1 and v2, Factur-X)
|
* filenames for invoice data (ZUGFeRD v1 and v2, Factur-X)
|
||||||
@@ -523,7 +553,8 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
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(XMLTools.trimOrNull(issueDateTimeChilds.item(issueDateChildIndex)));
|
String issueDateString = XMLTools.trimOrNull(issueDateTimeChilds.item(issueDateChildIndex));
|
||||||
|
issueDate = parseDate(issueDateString, "yyyyMMdd");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -582,15 +613,15 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
typeCode = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"InvoiceTypeCode\"]").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();
|
String issueDateStr = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"IssueDate\"]").trim();
|
||||||
if (!issueDateStr.isEmpty()) {
|
if (!issueDateStr.isEmpty()) {
|
||||||
issueDate = new SimpleDateFormat("yyyy-MM-dd").parse(issueDateStr);
|
issueDate = parseDate(issueDateStr, "yyyy-MM-dd");
|
||||||
}
|
}
|
||||||
String dueDt = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"DueDate\"]").trim();
|
String dueDt = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"DueDate\"]").trim();
|
||||||
if (!dueDt.isEmpty()) {
|
if (!dueDt.isEmpty()) {
|
||||||
dueDate = new SimpleDateFormat("yyyy-MM-dd").parse(dueDt);
|
dueDate = parseDate(dueDt, "yyyy-MM-dd");
|
||||||
}
|
}
|
||||||
String deliveryDt = extractString("//*[local-name()=\"Delivery\"]/*[local-name()=\"ActualDeliveryDate\"]").trim();
|
String deliveryDt = extractString("//*[local-name()=\"Delivery\"]/*[local-name()=\"ActualDeliveryDate\"]").trim();
|
||||||
if (!deliveryDt.isEmpty()) {
|
if (!deliveryDt.isEmpty()) {
|
||||||
deliveryDate = new SimpleDateFormat("yyyy-MM-dd").parse(deliveryDt);
|
deliveryDate = parseDate(deliveryDt, "yyyy-MM-dd");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,7 +651,8 @@ 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(XMLTools.trimOrNull(occurenceChilds.item(occurenceChildIndex)));
|
String deliveryDateString = XMLTools.trimOrNull(occurenceChilds.item(occurenceChildIndex));
|
||||||
|
deliveryDate = parseDate(deliveryDateString, "yyyyMMdd");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -714,7 +746,8 @@ 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(XMLTools.trimOrNull(dueDateChilds.item(dueDateChildIndex)));
|
String dueDateString = XMLTools.trimOrNull(dueDateChilds.item(dueDateChildIndex));
|
||||||
|
dueDate = parseDate(dueDateString, "yyyyMMdd");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -767,7 +800,7 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
if (BIC != null) {
|
if (BIC != null) {
|
||||||
bd.setBIC(BIC);
|
bd.setBIC(BIC);
|
||||||
}
|
}
|
||||||
if (accountName!=null) {
|
if (accountName != null) {
|
||||||
bd.setAccountName(accountName);
|
bd.setAccountName(accountName);
|
||||||
}
|
}
|
||||||
bankDetails.add(bd);
|
bankDetails.add(bd);
|
||||||
@@ -803,7 +836,7 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
NodeList periodNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
NodeList periodNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
|
||||||
for (int periodChildIndex = 0; periodChildIndex < periodNodes.getLength(); periodChildIndex++) {
|
for (int periodChildIndex = 0; periodChildIndex < periodNodes.getLength(); periodChildIndex++) {
|
||||||
String localName=periodNodes.item(periodChildIndex).getLocalName();
|
String localName = periodNodes.item(periodChildIndex).getLocalName();
|
||||||
if ((localName != null) && (periodNodes.item(periodChildIndex).getLocalName().equals("StartDate"))) {
|
if ((localName != null) && (periodNodes.item(periodChildIndex).getLocalName().equals("StartDate"))) {
|
||||||
deliveryPeriodStart = XMLTools.trimOrNull(periodNodes.item(periodChildIndex));
|
deliveryPeriodStart = XMLTools.trimOrNull(periodNodes.item(periodChildIndex));
|
||||||
}
|
}
|
||||||
@@ -854,7 +887,7 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
}
|
}
|
||||||
if (IBAN != null) {
|
if (IBAN != null) {
|
||||||
BankDetails bd = new BankDetails(IBAN);
|
BankDetails bd = new BankDetails(IBAN);
|
||||||
if (accountName!=null) {
|
if (accountName != null) {
|
||||||
bd.setAccountName(accountName);
|
bd.setAccountName(accountName);
|
||||||
}
|
}
|
||||||
bankDetails.add(bd);
|
bankDetails.add(bd);
|
||||||
@@ -1119,6 +1152,18 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Date parseDate(String issueDateString, String datePattern) throws ParseException {
|
||||||
|
Date parsedDate = null;
|
||||||
|
if (issueDateString != null) {
|
||||||
|
try {
|
||||||
|
parsedDate = new SimpleDateFormat(datePattern).parse(issueDateString);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
LOGGER.warn("Failed to parse date {} with pattern {}", issueDateString, datePattern, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parsedDate;
|
||||||
|
}
|
||||||
|
|
||||||
protected Document getDocument() {
|
protected Document getDocument() {
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
@@ -1201,7 +1246,7 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public List<FileAttachment> getFileAttachmentsXML() {
|
public List<FileAttachment> getFileAttachmentsXML() {
|
||||||
if (importedInvoice.getAdditionalReferencedDocuments()!=null) {
|
if (importedInvoice.getAdditionalReferencedDocuments() != null) {
|
||||||
return new ArrayList<>(Arrays.asList(importedInvoice.getAdditionalReferencedDocuments()));
|
return new ArrayList<>(Arrays.asList(importedInvoice.getAdditionalReferencedDocuments()));
|
||||||
} else {
|
} else {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
@@ -1228,7 +1273,7 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
* sets the XML for the importer to parse
|
* sets the XML for the importer to parse
|
||||||
* @param XML the UBL or CII
|
* @param XML the UBL or CII
|
||||||
*/
|
*/
|
||||||
public void fromXML(String XML) throws ParseException{
|
public void fromXML(String XML) throws ParseException {
|
||||||
try {
|
try {
|
||||||
containsMeta = true;
|
containsMeta = true;
|
||||||
setRawXML(XML.getBytes(StandardCharsets.UTF_8));
|
setRawXML(XML.getBytes(StandardCharsets.UTF_8));
|
||||||
|
|||||||
Reference in New Issue
Block a user