From 8094504fa533912098bdfedca7addb47ff8270ee Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 18 Oct 2021 15:27:50 +0200 Subject: [PATCH] make invoiceimporters namespace aware to be able to properly ignore namespaces --- History.md | 3 + .../ZUGFeRD/ZUGFeRDImporter.java | 98 ++++++++--------- .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 102 +++++++++++------- .../ZUGFeRD/ZF2ZInvoiceImporterTest.java | 31 +++++- 4 files changed, 145 insertions(+), 89 deletions(-) diff --git a/History.md b/History.md index de15da83..f50cbf45 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,6 @@ +- ZugferdInvoideImporter to be able to read XML, not only PDF +- ignore whitespace around numbers in invoiceimporter + 2.3.0 ======= 2021-10-04 diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java index 80d2f8ec..c586fe0d 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java @@ -180,7 +180,7 @@ public class ZUGFeRDImporter { private void setDocument() throws ParserConfigurationException, IOException, SAXException { final DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance(); - xmlFact.setNamespaceAware(false); + xmlFact.setNamespaceAware(true); final DocumentBuilder builder = xmlFact.newDocumentBuilder(); final ByteArrayInputStream is = new ByteArrayInputStream(rawXML); /// is.skip(guessBOMSize(is)); @@ -232,9 +232,9 @@ public class ZUGFeRDImporter { * @return the reference (purpose) the sender specified for this invoice */ public String getForeignReference() { - String result = extractString("//ApplicableHeaderTradeSettlement/PaymentReference"); + String result = extractString("//*[local-name() = 'ApplicableHeaderTradeSettlement']/*[local-name() = 'PaymentReference']"); if (result == null || result.isEmpty()) { - result = extractString("//ApplicableSupplyChainTradeSettlement/PaymentReference"); + result = extractString("//*[local-name() = 'ApplicableSupplyChainTradeSettlement']/*[local-name() = 'PaymentReference']"); } return result; } @@ -243,7 +243,7 @@ public class ZUGFeRDImporter { * @return the ZUGFeRD Profile */ public String getZUGFeRDProfil() { - switch (extractString("//GuidelineSpecifiedDocumentContextParameter//ID")) { + switch (extractString("//*[local-name() = 'GuidelineSpecifiedDocumentContextParameter']//*[local-name() = 'ID']")) { case "urn:cen.eu:en16931:2017": case "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort": return "COMFORT"; @@ -267,9 +267,9 @@ public class ZUGFeRDImporter { public String getInvoiceCurrencyCode() { try { if (getVersion() == 1) { - return extractString("//ApplicableSupplyChainTradeSettlement//InvoiceCurrencyCode"); + return extractString("//*[local-name() = 'ApplicableSupplyChainTradeSettlement']//*[local-name() = 'InvoiceCurrencyCode']"); } else { - return extractString("//ApplicableHeaderTradeSettlement//InvoiceCurrencyCode"); + return extractString("//*[local-name() = 'ApplicableHeaderTradeSettlement']//*[local-name() = 'InvoiceCurrencyCode']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -302,9 +302,9 @@ public class ZUGFeRDImporter { private String extractIssuerAssignedID(String propertyName) { try { if (getVersion() == 1) { - return extractString("//BuyerOrderReferencedDocument//ID"); + return extractString("//*[local-name() = 'BuyerOrderReferencedDocument']//*[local-name() = 'ID']"); } else { - return extractString("//BuyerOrderReferencedDocument//IssuerAssignedID"); + return extractString("//*[local-name() = 'BuyerOrderReferencedDocument']//*[local-name() = 'IssuerAssignedID']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -316,7 +316,7 @@ public class ZUGFeRDImporter { * @return the BuyerTradeParty ID */ public String getBuyerTradePartyID() { - return extractString("//BuyerTradeParty//ID"); + return extractString("//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'ID']"); } /** @@ -325,9 +325,9 @@ public class ZUGFeRDImporter { public String getIssueDate() { try { if (getVersion() == 1) { - return extractString("//HeaderExchangedDocument//IssueDateTime//DateTimeString"); + return extractString("//*[local-name() = 'HeaderExchangedDocument']//*[local-name() = 'IssueDateTime']//*[local-name() = 'DateTimeString']"); } else { - return extractString("//ExchangedDocument//IssueDateTime//DateTimeString"); + return extractString("//*[local-name() = 'ExchangedDocument']//*[local-name() = 'IssueDateTime']//*[local-name() = 'DateTimeString']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -341,9 +341,9 @@ public class ZUGFeRDImporter { public String getTaxBasisTotalAmount() { try { if (getVersion() == 1) { - return extractString("//SpecifiedTradeSettlementMonetarySummation//TaxBasisTotalAmount"); + return extractString("//*[local-name() = 'SpecifiedTradeSettlementMonetarySummation']//*[local-name() = 'TaxBasisTotalAmount']"); } else { - return extractString("//SpecifiedTradeSettlementHeaderMonetarySummation//TaxBasisTotalAmount"); + return extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']//*[local-name() = 'TaxBasisTotalAmount']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -357,9 +357,9 @@ public class ZUGFeRDImporter { public String getTaxTotalAmount() { try { if (getVersion() == 1) { - return extractString("//SpecifiedTradeSettlementMonetarySummation//TaxTotalAmount"); + return extractString("//*[local-name() = 'SpecifiedTradeSettlementMonetarySummation']//*[local-name() = 'TaxTotalAmount']"); } else { - return extractString("//SpecifiedTradeSettlementHeaderMonetarySummation//TaxTotalAmount"); + return extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']//*[local-name() = 'TaxTotalAmount']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -373,9 +373,9 @@ public class ZUGFeRDImporter { public String getRoundingAmount() { try { if (getVersion() == 1) { - return extractString("//SpecifiedTradeSettlementMonetarySummation//RoundingAmount"); + return extractString("//*[local-name() = 'SpecifiedTradeSettlementMonetarySummation']//*[local-name() = 'RoundingAmount']"); } else { - return extractString("//SpecifiedTradeSettlementHeaderMonetarySummation//RoundingAmount"); + return extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']//*[local-name() = 'RoundingAmount']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -389,9 +389,9 @@ public class ZUGFeRDImporter { public String getPaidAmount() { try { if (getVersion() == 1) { - return extractString("//SpecifiedTradeSettlementMonetarySummation//TotalPrepaidAmount"); + return extractString("//*[local-name() = 'SpecifiedTradeSettlementMonetarySummation']//*[local-name() = 'TotalPrepaidAmount']"); } else { - return extractString("//SpecifiedTradeSettlementHeaderMonetarySummation//TotalPrepaidAmount"); + return extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']//*[local-name() = 'TotalPrepaidAmount']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -403,21 +403,21 @@ public class ZUGFeRDImporter { * @return SellerTradeParty GlobalID */ public String getSellerTradePartyGlobalID() { - return extractString("//SellerTradeParty//GlobalID"); + return extractString("//*[local-name() = 'SellerTradeParty']//*[local-name() = 'GlobalID']"); } /** * @return the BuyerTradeParty GlobalID */ public String getBuyerTradePartyGlobalID() { - return extractString("//BuyerTradeParty//GlobalID"); + return extractString("//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'GlobalID']"); } /** * @return the BuyerTradeParty SpecifiedTaxRegistration ID */ public String getBuyertradePartySpecifiedTaxRegistrationID() { - return extractString("//BuyerTradeParty//SpecifiedTaxRegistration//ID"); + return extractString("//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'SpecifiedTaxRegistration']//*[local-name() = 'ID']"); } @@ -427,9 +427,9 @@ public class ZUGFeRDImporter { public String getIncludedNote() { try { if (getVersion() == 1) { - return extractString("//HeaderExchangedDocument//IncludedNote"); + return extractString("//*[local-name() = 'HeaderExchangedDocument']//*[local-name() = 'IncludedNote']"); } else { - return extractString("//ExchangedDocument//IncludedNote"); + return extractString("//*[local-name() = 'ExchangedDocument']//*[local-name() = 'IncludedNote']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -441,7 +441,7 @@ public class ZUGFeRDImporter { * @return the BuyerTradeParty Name */ public String getBuyerTradePartyName() { - return extractString("//BuyerTradeParty//Name"); + return extractString("//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'Name']"); } @@ -452,9 +452,9 @@ public class ZUGFeRDImporter { public String getLineTotalAmount() { try { if (getVersion() == 1) { - return extractString("//SpecifiedTradeSettlementMonetarySummation//LineTotalAmount"); + return extractString("//*[local-name() = 'SpecifiedTradeSettlementMonetarySummation']//*[local-name() = 'LineTotalAmount']"); } else { - return extractString("//SpecifiedTradeSettlementHeaderMonetarySummation//LineTotalAmount"); + return extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']//*[local-name() = 'LineTotalAmount']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -466,7 +466,7 @@ public class ZUGFeRDImporter { * @return the Payment Terms */ public String getPaymentTerms() { - return extractString("//SpecifiedTradePaymentTerms//Description"); + return extractString("//*[local-name() = 'SpecifiedTradePaymentTerms']//*[local-name() = 'Description']"); } /** @@ -475,9 +475,9 @@ public class ZUGFeRDImporter { public String getTaxPointDate() { try { if (getVersion() == 1) { - return extractString("//ActualDeliverySupplyChainEvent//OccurrenceDateTime//DateTimeString"); + return extractString("//*[local-name() = 'ActualDeliverySupplyChainEvent']//*[local-name() = 'OccurrenceDateTime']//*[local-name() = 'DateTimeString']"); } else { - return extractString("//ActualDeliverySupplyChainEvent//OccurrenceDateTime//DateTimeString"); + return extractString("//*[local-name() = 'ActualDeliverySupplyChainEvent']//*[local-name() = 'OccurrenceDateTime']//*[local-name() = 'DateTimeString']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -491,9 +491,9 @@ public class ZUGFeRDImporter { public String getInvoiceID() { try { if (getVersion() == 1) { - return extractString("//HeaderExchangedDocument//ID"); + return extractString("//*[local-name() = 'HeaderExchangedDocument']//*[local-name() = 'ID']"); } else { - return extractString("//ExchangedDocument//ID"); + return extractString("//*[local-name() = 'ExchangedDocument']//*[local-name() = 'ID']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -509,9 +509,9 @@ public class ZUGFeRDImporter { public String getDocumentCode() { try { if (getVersion() == 1) { - return extractString("//HeaderExchangedDocument/TypeCode"); + return extractString("//*[local-name() = 'HeaderExchangedDocument']/*[local-name() = 'TypeCode']"); } else { - return extractString("//ExchangedDocument/TypeCode"); + return extractString("//*[local-name() = 'ExchangedDocument']/*[local-name() = 'TypeCode']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -526,9 +526,9 @@ public class ZUGFeRDImporter { public String getReference() { try { if (getVersion() == 1) { - return extractString("//ApplicableSupplyChainTradeAgreement/BuyerReference"); + return extractString("//*[local-name() = 'ApplicableSupplyChainTradeAgreement']/*[local-name() = 'BuyerReference']"); } else { - return extractString("//ApplicableHeaderTradeAgreement/BuyerReference"); + return extractString("//*[local-name() = 'ApplicableHeaderTradeAgreement']/*[local-name() = 'BuyerReference']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -541,7 +541,7 @@ public class ZUGFeRDImporter { * @return the sender's bank's BIC code */ public String getBIC() { - return extractString("//PayeeSpecifiedCreditorFinancialInstitution/BICID"); + return extractString("//*[local-name() = 'PayeeSpecifiedCreditorFinancialInstitution']/*[local-name() = 'BICID']"); } @@ -549,7 +549,7 @@ public class ZUGFeRDImporter { * @return the sender's bank name */ public String getBankName() { - return extractString("//PayeeSpecifiedCreditorFinancialInstitution/Name"); + return extractString("//*[local-name() = 'PayeeSpecifiedCreditorFinancialInstitution']/*[local-name() = 'Name']"); } @@ -557,12 +557,12 @@ public class ZUGFeRDImporter { * @return the sender's account IBAN code */ public String getIBAN() { - return extractString("//PayeePartyCreditorFinancialAccount/IBANID"); + return extractString("//*[local-name() = 'PayeePartyCreditorFinancialAccount']/*[local-name() = 'IBANID']"); } public String getHolder() { - return extractString("//SellerTradeParty/Name"); + return extractString("//*[local-name() = 'SellerTradeParty']/*[local-name() = 'Name']"); } @@ -570,9 +570,9 @@ public class ZUGFeRDImporter { * @return the total payable amount */ public String getAmount() { - String result = extractString("//SpecifiedTradeSettlementHeaderMonetarySummation/DuePayableAmount"); + String result = extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']/*[local-name() = 'DuePayableAmount']"); if (result == null || result.isEmpty()) { - result = extractString("//SpecifiedTradeSettlementMonetarySummation/GrandTotalAmount"); + result = extractString("//*[local-name() = 'SpecifiedTradeSettlementMonetarySummation']/*[local-name() = 'GrandTotalAmount']"); } return result; } @@ -582,7 +582,7 @@ public class ZUGFeRDImporter { * @return when the payment is due */ public String getDueDate() { - return extractString("//SpecifiedTradePaymentTerms/DueDateDateTime/DateTimeString"); + return extractString("//*[local-name() = 'SpecifiedTradePaymentTerms']/*[local-name() = 'DueDateDateTime']/*[local-name() = 'DateTimeString']"); } @@ -714,9 +714,9 @@ public class ZUGFeRDImporter { try { if (getVersion() == 1) { - nl = getNodeListByPath("//CrossIndustryDocument//SpecifiedSupplyChainTradeTransaction//ApplicableSupplyChainTradeAgreement//BuyerTradeParty//PostalTradeAddress"); + nl = getNodeListByPath("//*[local-name() = 'CrossIndustryDocument']//*[local-name() = 'SpecifiedSupplyChainTradeTransaction/']/*[local-name() = 'ApplicableSupplyChainTradeAgreement']//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'PostalTradeAddress']"); } else { - nl = getNodeListByPath("//CrossIndustryInvoice//SupplyChainTradeTransaction//ApplicableHeaderTradeAgreement//BuyerTradeParty//PostalTradeAddress"); + nl = getNodeListByPath("//*[local-name() = 'CrossIndustryInvoice']//*[local-name() = 'SupplyChainTradeTransaction']//*[local-name() = 'ApplicableHeaderTradeAgreement']//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'PostalTradeAddress']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -737,9 +737,9 @@ public class ZUGFeRDImporter { try { if (getVersion() == 1) { - nl = getNodeListByPath("//CrossIndustryDocument//SpecifiedSupplyChainTradeTransaction//ApplicableSupplyChainTradeAgreement//SellerTradeParty//PostalTradeAddress"); + nl = getNodeListByPath("//*[local-name() = 'CrossIndustryDocument']//*[local-name() = 'SpecifiedSupplyChainTradeTransaction']//*[local-name() = 'ApplicableSupplyChainTradeAgreement']//*[local-name() = 'SellerTradeParty']//*[local-name() = 'PostalTradeAddress']"); } else { - nl = getNodeListByPath("//CrossIndustryInvoice//SupplyChainTradeTransaction//ApplicableHeaderTradeAgreement//SellerTradeParty//PostalTradeAddress"); + nl = getNodeListByPath("//*[local-name() = 'CrossIndustryInvoice']//*[local-name() = 'SupplyChainTradeTransaction']//*[local-name() = 'ApplicableHeaderTradeAgreement']//*[local-name() = 'SellerTradeParty']//*[local-name() = 'PostalTradeAddress']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -936,9 +936,9 @@ public class ZUGFeRDImporter { NodeList nl = null; try { if (getVersion() == 1) { - nl = getNodeListByPath("//CrossIndustryDocument//SpecifiedSupplyChainTradeTransaction//IncludedSupplyChainTradeLineItem"); + nl = getNodeListByPath("//*[local-name() = 'CrossIndustryDocument']//*[local-name() = 'SpecifiedSupplyChainTradeTransaction']//*[local-name() = 'IncludedSupplyChainTradeLineItem']"); } else { - nl = getNodeListByPath("//CrossIndustryInvoice//SupplyChainTradeTransaction//IncludedSupplyChainTradeLineItem"); + nl = getNodeListByPath("//*[local-name() = 'CrossIndustryInvoice']//*[local-name() = 'SupplyChainTradeTransaction']//*[local-name() = 'IncludedSupplyChainTradeLineItem']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 172cc6cb..f4acd281 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -1,21 +1,41 @@ package org.mustangproject.ZUGFeRD; +import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile; import org.mustangproject.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.xml.xpath.*; +import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter { + private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRDInvoiceImporter.class.getCanonicalName()); // log + + public ZUGFeRDInvoiceImporter() { + super(); + } + public ZUGFeRDInvoiceImporter(String filename) { super(filename); } + public void fromXML(String XML) { + try { + containsMeta = true; + setRawXML(XML.getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + LOGGER.error(e.getMessage(), e); + } + } + /*** * This will parse a XML into a invoice object * @return the parsed invoice object @@ -58,13 +78,13 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter { Node exchangedDocumentNode = ExchangedDocumentNodes.item(i); NodeList exchangedDocumentChilds = exchangedDocumentNode.getChildNodes(); for (int documentChildIndex = 0; documentChildIndex < exchangedDocumentChilds.getLength(); documentChildIndex++) { - if (exchangedDocumentChilds.item(documentChildIndex).getNodeName().equals("ram:ID")) { + if ((exchangedDocumentChilds.item(documentChildIndex).getLocalName() != null) && (exchangedDocumentChilds.item(documentChildIndex).getLocalName().equals("ID"))) { number = exchangedDocumentChilds.item(documentChildIndex).getTextContent(); } - if (exchangedDocumentChilds.item(documentChildIndex).getNodeName().equals("ram:IssueDateTime")) { + if ((exchangedDocumentChilds.item(documentChildIndex).getLocalName() != null) && (exchangedDocumentChilds.item(documentChildIndex).getLocalName().equals("IssueDateTime"))) { NodeList issueDateTimeChilds = exchangedDocumentChilds.item(documentChildIndex).getChildNodes(); for (int issueDateChildIndex = 0; issueDateChildIndex < issueDateTimeChilds.getLength(); issueDateChildIndex++) { - if (issueDateTimeChilds.item(issueDateChildIndex).getNodeName().equals("udt:DateTimeString")) { + if ((issueDateTimeChilds.item(issueDateChildIndex).getLocalName()!=null)&&(issueDateTimeChilds.item(issueDateChildIndex).getLocalName().equals("DateTimeString"))) { issueDate = new SimpleDateFormat("yyyyMMdd").parse(issueDateTimeChilds.item(issueDateChildIndex).getTextContent()); } } @@ -82,15 +102,14 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter { Node headerTradeDeliveryNode = headerTradeDeliveryNodes.item(i); NodeList headerTradeDeliveryChilds = headerTradeDeliveryNode.getChildNodes(); for (int deliveryChildIndex = 0; deliveryChildIndex < headerTradeDeliveryChilds.getLength(); deliveryChildIndex++) { - if (headerTradeDeliveryChilds.item(deliveryChildIndex).getNodeName().equals("ram:ActualDeliverySupplyChainEvent")) { + if ((headerTradeDeliveryChilds.item(deliveryChildIndex).getLocalName() != null) && (headerTradeDeliveryChilds.item(deliveryChildIndex).getLocalName().equals("ActualDeliverySupplyChainEvent"))) { NodeList actualDeliveryChilds = headerTradeDeliveryChilds.item(deliveryChildIndex).getChildNodes(); for (int actualDeliveryChildIndex = 0; actualDeliveryChildIndex < actualDeliveryChilds.getLength(); actualDeliveryChildIndex++) { - if (actualDeliveryChilds.item(actualDeliveryChildIndex).getNodeName().equals("ram:OccurrenceDateTime")) { + if ((actualDeliveryChilds.item(actualDeliveryChildIndex).getLocalName() != null) && (actualDeliveryChilds.item(actualDeliveryChildIndex).getLocalName().equals("OccurrenceDateTime"))) { NodeList occurenceChilds = actualDeliveryChilds.item(actualDeliveryChildIndex).getChildNodes(); for (int occurenceChildIndex = 0; occurenceChildIndex < occurenceChilds.getLength(); occurenceChildIndex++) { - if (occurenceChilds.item(occurenceChildIndex).getNodeName().equals("udt:DateTimeString")) { + if ((occurenceChilds.item(occurenceChildIndex).getLocalName() != null) && (occurenceChilds.item(occurenceChildIndex).getLocalName().equals("DateTimeString"))) { deliveryDate = new SimpleDateFormat("yyyyMMdd").parse(occurenceChilds.item(occurenceChildIndex).getTextContent()); - } } } @@ -109,15 +128,14 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter { Node headerTradeSettlementNode = headerTradeSettlementNodes.item(i); NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes(); for (int settlementChildIndex = 0; settlementChildIndex < headerTradeSettlementChilds.getLength(); settlementChildIndex++) { - if (headerTradeSettlementChilds.item(settlementChildIndex).getNodeName().equals("ram:SpecifiedTradePaymentTerms")) { + if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null) && (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("SpecifiedTradePaymentTerms"))) { NodeList paymentTermChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes(); for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds.getLength(); paymentTermChildIndex++) { - if (paymentTermChilds.item(paymentTermChildIndex).getNodeName().equals("ram:DueDateDateTime")) { + if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("DueDateDateTime"))) { NodeList dueDateChilds = paymentTermChilds.item(paymentTermChildIndex).getChildNodes(); for (int dueDateChildIndex = 0; dueDateChildIndex < dueDateChilds.getLength(); dueDateChildIndex++) { - if (dueDateChilds.item(dueDateChildIndex).getNodeName().equals("udt:DateTimeString")) { + if ((dueDateChilds.item(dueDateChildIndex).getLocalName() != null) && (dueDateChilds.item(dueDateChildIndex).getLocalName().equals("DateTimeString"))) { dueDate = new SimpleDateFormat("yyyyMMdd").parse(dueDateChilds.item(dueDateChildIndex).getTextContent()); - } } } @@ -128,7 +146,7 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter { zpp = new Invoice().setDueDate(dueDate).setDeliveryDate(deliveryDate).setIssueDate(issueDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number); //.addItem(new Item(new Product("Testprodukt","","C62",BigDecimal.ZERO),amount,new BigDecimal(1.0))) - zpp.setOwnOrganisationName(extractString("//SellerTradeParty/Name")); + zpp.setOwnOrganisationName(extractString("//*[local-name()=\"SellerTradeParty\"]/*[local-name()=\"Name\"]")); xpr = xpath.compile( "//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]"); NodeList nodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); @@ -148,44 +166,45 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter { Node currentItemNode = nodes.item(i); NodeList itemChilds = currentItemNode.getChildNodes(); for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) { - if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeAgreement")) { + if ((itemChilds.item(itemChildIndex).getLocalName() != null) && (itemChilds.item(itemChildIndex).getLocalName().equals("SpecifiedLineTradeAgreement"))) { NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes(); for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds.getLength(); tradeLineChildIndex++) { - if (tradeLineChilds.item(tradeLineChildIndex).getNodeName().equals("ram:NetPriceProductTradePrice")) { + if ((tradeLineChilds.item(tradeLineChildIndex).getLocalName()!=null)&&tradeLineChilds.item(tradeLineChildIndex).getLocalName().equals("NetPriceProductTradePrice")) { NodeList netChilds = tradeLineChilds.item(tradeLineChildIndex).getChildNodes(); for (int netIndex = 0; netIndex < netChilds.getLength(); netIndex++) { - if (netChilds.item(netIndex).getNodeName().equals("ram:ChargeAmount")) { - price = netChilds.item(netIndex).getTextContent();//ram:ChargeAmount + if ((netChilds.item(netIndex).getLocalName() != null) && (netChilds.item(netIndex).getLocalName().equals("ChargeAmount"))) { + price = netChilds.item(netIndex).getTextContent();//ChargeAmount } } } } } - if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeDelivery")) { + if ((itemChilds.item(itemChildIndex).getLocalName() != null) && (itemChilds.item(itemChildIndex).getLocalName().equals("SpecifiedLineTradeDelivery"))) { NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes(); for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds.getLength(); tradeLineChildIndex++) { - if (tradeLineChilds.item(tradeLineChildIndex).getNodeName().equals("ram:BilledQuantity")) { + if ((tradeLineChilds.item(tradeLineChildIndex).getLocalName() != null) && (tradeLineChilds.item(tradeLineChildIndex).getLocalName().equals("BilledQuantity"))) { quantity = tradeLineChilds.item(tradeLineChildIndex).getTextContent(); unitCode = tradeLineChilds.item(tradeLineChildIndex).getAttributes().getNamedItem("unitCode").getNodeValue(); } } } - if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedTradeProduct")) { + if ((itemChilds.item(itemChildIndex).getLocalName() != null) && (itemChilds.item(itemChildIndex).getLocalName().equals("SpecifiedTradeProduct"))) { NodeList tradeProductChilds = itemChilds.item(itemChildIndex).getChildNodes(); for (int tradeProductChildIndex = 0; tradeProductChildIndex < tradeProductChilds.getLength(); tradeProductChildIndex++) { - if (tradeProductChilds.item(tradeProductChildIndex).getNodeName().equals("ram:Name")) { + if ((tradeProductChilds.item(tradeProductChildIndex).getLocalName() != null) && (tradeProductChilds.item(tradeProductChildIndex).getLocalName().equals("Name"))) + { name = tradeProductChilds.item(tradeProductChildIndex).getTextContent(); } } } - if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeSettlement")) { + if ((itemChilds.item(itemChildIndex).getLocalName() != null) && (itemChilds.item(itemChildIndex).getLocalName().equals("SpecifiedLineTradeSettlement"))) { NodeList tradeSettlementChilds = itemChilds.item(itemChildIndex).getChildNodes(); for (int tradeSettlementChildIndex = 0; tradeSettlementChildIndex < tradeSettlementChilds.getLength(); tradeSettlementChildIndex++) { - if (tradeSettlementChilds.item(tradeSettlementChildIndex).getNodeName().equals("ram:ApplicableTradeTax")) { + if ((tradeSettlementChilds.item(tradeSettlementChildIndex).getLocalName() != null) && (tradeSettlementChilds.item(tradeSettlementChildIndex).getLocalName().equals("ApplicableTradeTax"))) { NodeList taxChilds = tradeSettlementChilds.item(tradeSettlementChildIndex).getChildNodes(); for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) { - if (taxChilds.item(taxChildIndex).getNodeName().equals("ram:RateApplicablePercent")) { + if ((taxChilds.item(taxChildIndex).getLocalName() != null) && (taxChilds.item(taxChildIndex).getLocalName().equals("RateApplicablePercent"))) { vatPercent = taxChilds.item(taxChildIndex).getTextContent(); } } @@ -195,7 +214,7 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter { } - zpp.addItem(new Item(new Product(name, description, unitCode, new BigDecimal(vatPercent)), new BigDecimal(price), new BigDecimal(quantity))); + zpp.addItem(new Item(new Product(name, description, unitCode, new BigDecimal(vatPercent.trim())), new BigDecimal(price.trim()), new BigDecimal(quantity.trim()))); } } @@ -213,26 +232,31 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter { String reason = null; String taxPercent = null; for (int chargeChildIndex = 0; chargeChildIndex < chargeNodeChilds.getLength(); chargeChildIndex++) { - if (chargeNodeChilds.item(chargeChildIndex).getNodeName().equals("ram:ChargeIndicator")) { - NodeList indicatorChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes(); - for (int indicatorChildIndex = 0; indicatorChildIndex < indicatorChilds.getLength(); indicatorChildIndex++) { - if (indicatorChilds.item(indicatorChildIndex).getNodeName().equals("udt:Indicator")) { - isCharge = indicatorChilds.item(indicatorChildIndex).getTextContent().equalsIgnoreCase("true"); + if (chargeNodeChilds.item(chargeChildIndex).getLocalName() != null) { + + if (chargeNodeChilds.item(chargeChildIndex).getLocalName().equals("ChargeIndicator")) { + NodeList indicatorChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes(); + for (int indicatorChildIndex = 0; indicatorChildIndex < indicatorChilds.getLength(); indicatorChildIndex++) { + if (indicatorChilds.item(indicatorChildIndex).getLocalName().equals("Indicator")) { + isCharge = indicatorChilds.item(indicatorChildIndex).getTextContent().equalsIgnoreCase("true"); + } } - } - } else if (chargeNodeChilds.item(chargeChildIndex).getNodeName().equals("ram:ActualAmount")) { - chargeAmount = chargeNodeChilds.item(chargeChildIndex).getTextContent(); - } else if (chargeNodeChilds.item(chargeChildIndex).getNodeName().equals("ram:Reason")) { - reason = chargeNodeChilds.item(chargeChildIndex).getTextContent(); - } else if (chargeNodeChilds.item(chargeChildIndex).getNodeName().equals("ram:CategoryTradeTax")) { - NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes(); - for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) { - if (taxChilds.item(taxChildIndex).getNodeName().equals("ram:RateApplicablePercent")) { - taxPercent = taxChilds.item(taxChildIndex).getTextContent(); + } else if (chargeNodeChilds.item(chargeChildIndex).getLocalName().equals("ActualAmount")) { + chargeAmount = chargeNodeChilds.item(chargeChildIndex).getTextContent(); + } else if (chargeNodeChilds.item(chargeChildIndex).getLocalName().equals("Reason")) { + reason = chargeNodeChilds.item(chargeChildIndex).getTextContent(); + } else if (chargeNodeChilds.item(chargeChildIndex).getLocalName().equals("CategoryTradeTax")) { + NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes(); + for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) { + if ((taxChilds.item(taxChildIndex).getLocalName() != null) && (taxChilds.item(taxChildIndex).getLocalName().equals("RateApplicablePercent"))) + { + taxPercent = taxChilds.item(taxChildIndex).getTextContent(); + } } } } + } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index 668b8094..e58241d7 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -19,12 +19,23 @@ *********************************************************************** */ package org.mustangproject.ZUGFeRD; +import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile; import org.mustangproject.Invoice; import junit.framework.TestCase; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathExpressionException; +import java.io.IOException; +import java.io.StringReader; import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -33,7 +44,7 @@ import java.text.SimpleDateFormat; * Classname ZF2ZInvoiceImporterTest is alphabetical behind the tests which will create the file * used for this import, testout-ZF2New.pdf */ -public class ZF2ZInvoiceImporterTest extends TestCase { +public class ZF2ZInvoiceImporterTest extends ResourceCase { public void testInvoiceImport() { @@ -119,6 +130,24 @@ public class ZF2ZInvoiceImporterTest extends TestCase { } + public void testItemReferencedDocumentsImport() { + ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter(); + + DocumentBuilderFactory db = DocumentBuilderFactory.newInstance(); + + boolean hasExceptions=false; + Invoice invoice=null; + try { + zii.fromXML(new String(Files.readAllBytes(Paths.get(getResourceAsFile("factur-x-testImport.xml").getAbsolutePath())), StandardCharsets.UTF_8)); + invoice=zii.extractInvoice(); + } catch (XPathExpressionException | ParseException | IOException e) { + hasExceptions=true; + } + assertFalse(hasExceptions); + TransactionCalculator tc=new TransactionCalculator(invoice); + assertEquals(new BigDecimal("1284.66"),tc.getGrandTotal()); + + } }