importing first attribute (price) of invoice line items

This commit is contained in:
Jochen Stärk
2020-05-09 13:45:28 +02:00
parent 35551f0ed3
commit 8500d0c1cb
3 changed files with 580 additions and 452 deletions

View File

@@ -1,452 +1,452 @@
/** /**
* ********************************************************************** Copyright 2018 Jochen Staerk Use is subject to license terms. Licensed under the * ********************************************************************** Copyright 2018 Jochen Staerk Use is subject to license terms. Licensed under the
* Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at * Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * http://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
* and limitations under the License. * and limitations under the License.
*/ */
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
/** /**
* Mustangproject's ZUGFeRD implementation ZUGFeRD importer Licensed under the APLv2 * Mustangproject's ZUGFeRD implementation ZUGFeRD importer Licensed under the APLv2
* *
* @date 2014-07-07 * @date 2014-07-07
* @version 1.1.0 * @version 1.1.0
* @author jstaerk * @author jstaerk
*/ */
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Scanner; import java.util.Scanner;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
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.XPath; import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathFactory;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary; import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode; 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.w3c.dom.Document; import org.w3c.dom.Document;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
public class ZUGFeRDImporter { public class ZUGFeRDImporter {
/** /**
* if metadata has been found * if metadata has been found
*/ */
private boolean containsMeta = false; private boolean containsMeta = false;
/** /**
* map filenames of additional XML files to their contents * map filenames of additional XML files to their contents
*/ */
private HashMap<String, byte[]> additionalXMLs = new HashMap<>(); private HashMap<String, byte[]> additionalXMLs = new HashMap<>();
/** /**
* Raw XML form of the extracted data - may be directly obtained. * Raw XML form of the extracted data - may be directly obtained.
*/ */
private byte[] rawXML = null; private byte[] rawXML = null;
/** /**
* XMP metadata * XMP metadata
*/ */
private String xmpString = null; // XMP metadata private String xmpString = null; // XMP metadata
/** /**
* parsed Document * parsed Document
*/ */
private Document document; private Document document;
public ZUGFeRDImporter(String pdfFilename) { public ZUGFeRDImporter(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);
} catch (IOException e) { } catch (IOException e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
throw new ZUGFeRDExportException(e); throw new ZUGFeRDExportException(e);
} }
} }
public ZUGFeRDImporter(InputStream pdfStream) { public ZUGFeRDImporter(InputStream pdfStream) {
try { try {
extractLowLevel(pdfStream); extractLowLevel(pdfStream);
} catch (IOException e) { } catch (IOException e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
throw new ZUGFeRDExportException(e); throw new ZUGFeRDExportException(e);
} }
} }
/** /**
* Extracts a ZUGFeRD invoice from a PDF document represented by an input stream. Errors are reported via exception handling. * Extracts a ZUGFeRD invoice from a PDF document represented by an input stream. Errors are reported via exception handling.
* *
* @param pdfStream a inputstream of a pdf file * @param pdfStream a inputstream of a pdf file
*/ */
private void extractLowLevel(InputStream pdfStream) throws IOException { private void extractLowLevel(InputStream pdfStream) throws IOException {
try (PDDocument doc = PDDocument.load(pdfStream)) { try (PDDocument doc = PDDocument.load(pdfStream)) {
// PDDocumentInformation info = doc.getDocumentInformation(); // PDDocumentInformation info = doc.getDocumentInformation();
PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog()); PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
//start //start
if (doc.getDocumentCatalog() == null || doc.getDocumentCatalog().getMetadata() == null) { if (doc.getDocumentCatalog() == null || doc.getDocumentCatalog().getMetadata() == null) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.INFO, "no-xmlpart"); Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.INFO, "no-xmlpart");
return; return;
} }
InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata(); InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata();
xmpString = convertStreamToString(XMP); xmpString = convertStreamToString(XMP);
PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles(); PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles();
if (etn == null) { if (etn == null) {
return; return;
} }
Map<String, PDComplexFileSpecification> efMap = etn.getNames(); Map<String, PDComplexFileSpecification> efMap = etn.getNames();
// String filePath = "/tmp/"; // String filePath = "/tmp/";
if (efMap != null) { if (efMap != null) {
extractFiles(efMap); // see extractFiles(efMap); // see
// https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/ // https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/
} else { } else {
List<PDNameTreeNode<PDComplexFileSpecification>> kids = etn.getKids(); List<PDNameTreeNode<PDComplexFileSpecification>> kids = etn.getKids();
for (PDNameTreeNode<PDComplexFileSpecification> node : kids) { for (PDNameTreeNode<PDComplexFileSpecification> node : kids) {
Map<String, PDComplexFileSpecification> namesL = node.getNames(); Map<String, PDComplexFileSpecification> namesL = node.getNames();
extractFiles(namesL); extractFiles(namesL);
} }
} }
} }
} }
private void extractFiles(Map<String, PDComplexFileSpecification> names) throws IOException { private void extractFiles(Map<String, PDComplexFileSpecification> names) throws IOException {
for (String alias : names.keySet()) { for (String alias : names.keySet()) {
PDComplexFileSpecification fileSpec = names.get(alias); PDComplexFileSpecification fileSpec = names.get(alias);
String filename = fileSpec.getFilename(); String filename = fileSpec.getFilename();
/** /**
* filenames for invoice data (ZUGFeRD v1 and v2, Factur-X) * filenames for invoice data (ZUGFeRD v1 and v2, Factur-X)
*/ */
if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml"))) { //$NON-NLS-1$ if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml"))) { //$NON-NLS-1$
containsMeta = true; containsMeta = true;
PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile(); PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
// String embeddedFilename = filePath + filename; // String embeddedFilename = filePath + filename;
// File file = new File(filePath + filename); // File file = new File(filePath + filename);
// System.out.println("Writing " + embeddedFilename); // System.out.println("Writing " + embeddedFilename);
// ByteArrayOutputStream fileBytes=new // ByteArrayOutputStream fileBytes=new
// ByteArrayOutputStream(); // ByteArrayOutputStream();
// FileOutputStream fos = new FileOutputStream(file); // FileOutputStream fos = new FileOutputStream(file);
setRawXML(embeddedFile.toByteArray()); setRawXML(embeddedFile.toByteArray());
// fos.write(embeddedFile.getByteArray()); // fos.write(embeddedFile.getByteArray());
// fos.close(); // fos.close();
} }
if (filename.startsWith("additional_data")) { if (filename.startsWith("additional_data")) {
PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile(); PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
additionalXMLs.put(filename, embeddedFile.toByteArray()); additionalXMLs.put(filename, embeddedFile.toByteArray());
} }
} }
} }
private Document getDocument() { protected Document getDocument() {
return document; return document;
} }
private void setDocument() throws ParserConfigurationException, IOException, SAXException { private void setDocument() throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
xmlFact.setNamespaceAware(false); xmlFact.setNamespaceAware(false);
DocumentBuilder builder = xmlFact.newDocumentBuilder(); DocumentBuilder builder = xmlFact.newDocumentBuilder();
ByteArrayInputStream is = new ByteArrayInputStream(rawXML); ByteArrayInputStream is = new ByteArrayInputStream(rawXML);
is.skip(guessBOMSize(is)); is.skip(guessBOMSize(is));
document = builder.parse(is); document = builder.parse(is);
} }
public void setRawXML(byte[] rawXML) throws IOException { public void setRawXML(byte[] rawXML) throws IOException {
this.rawXML = rawXML; this.rawXML = rawXML;
try { try {
setDocument(); setDocument();
} catch (ParserConfigurationException | SAXException e) { } catch (ParserConfigurationException | SAXException e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
throw new ZUGFeRDExportException(e); throw new ZUGFeRDExportException(e);
} }
} }
/** /**
* Skips over a BOM at the beginning of the given ByteArrayInputStream, if one exists. * Skips over a BOM at the beginning of the given ByteArrayInputStream, if one exists.
* *
* @param is the ByteArrayInputStream used * @param is the ByteArrayInputStream used
* @throws IOException if can not be read from is * @throws IOException if can not be read from is
* @see <a href="https://www.w3.org/TR/xml/#sec-guessing">Autodetection of Character Encodings</a> * @see <a href="https://www.w3.org/TR/xml/#sec-guessing">Autodetection of Character Encodings</a>
*/ */
private int guessBOMSize(ByteArrayInputStream is) throws IOException { private int guessBOMSize(ByteArrayInputStream is) throws IOException {
byte[] pad = new byte[4]; byte[] pad = new byte[4];
is.read(pad); is.read(pad);
is.reset(); is.reset();
int test2 = ((pad[0] & 0xFF) << 8) | (pad[1] & 0xFF); int test2 = ((pad[0] & 0xFF) << 8) | (pad[1] & 0xFF);
int test3 = ((test2 & 0xFFFF) << 8) | (pad[2] & 0xFF); int test3 = ((test2 & 0xFFFF) << 8) | (pad[2] & 0xFF);
int test4 = ((test3 & 0xFFFFFF) << 8) | (pad[3] & 0xFF); int test4 = ((test3 & 0xFFFFFF) << 8) | (pad[3] & 0xFF);
// //
if (test4 == 0x0000FEFF || test4 == 0xFFFE0000 || test4 == 0x0000FFFE || test4 == 0xFEFF0000) { if (test4 == 0x0000FEFF || test4 == 0xFFFE0000 || test4 == 0x0000FFFE || test4 == 0xFEFF0000) {
// UCS-4: BOM takes 4 bytes // UCS-4: BOM takes 4 bytes
return 4; return 4;
} else if (test3 == 0xEFBBFF) { } else if (test3 == 0xEFBBFF) {
// UTF-8: BOM takes 3 bytes // UTF-8: BOM takes 3 bytes
return 3; return 3;
} else if (test2 == 0xFEFF || test2 == 0xFFFE) { } else if (test2 == 0xFEFF || test2 == 0xFFFE) {
// UTF-16: BOM takes 2 bytes // UTF-16: BOM takes 2 bytes
return 2; return 2;
} }
return 0; return 0;
} }
private String extractString(String xpathStr) { protected String extractString(String xpathStr) {
if (!containsMeta) { if (!containsMeta) {
throw new ZUGFeRDExportException("No suitable data/ZUGFeRD file could be found."); throw new ZUGFeRDExportException("No suitable data/ZUGFeRD file could be found.");
} }
String result; String result;
try { try {
Document document = getDocument(); Document document = getDocument();
XPathFactory xpathFact = XPathFactory.newInstance(); XPathFactory xpathFact = XPathFactory.newInstance();
XPath xpath = xpathFact.newXPath(); XPath xpath = xpathFact.newXPath();
result = xpath.evaluate(xpathStr, document); result = xpath.evaluate(xpathStr, document);
} catch (XPathExpressionException e) { } catch (XPathExpressionException e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
throw new ZUGFeRDExportException(e); throw new ZUGFeRDExportException(e);
} }
return result; return result;
} }
/** /**
* @return the reference (purpose) the sender specified for this invoice * @return the reference (purpose) the sender specified for this invoice
*/ */
public String getForeignReference() { public String getForeignReference() {
String result = extractString("//ApplicableHeaderTradeSettlement/PaymentReference"); String result = extractString("//ApplicableHeaderTradeSettlement/PaymentReference");
if (result == null || result.isEmpty()) { if (result == null || result.isEmpty()) {
result = extractString("//ApplicableSupplyChainTradeSettlement/PaymentReference"); result = extractString("//ApplicableSupplyChainTradeSettlement/PaymentReference");
} }
return result; return result;
} }
/** /**
* @return the document code * @return the document code
*/ */
public String getDocumentCode() { public String getDocumentCode() {
return extractString("//HeaderExchangedDocument/TypeCode"); return extractString("//HeaderExchangedDocument/TypeCode");
} }
/** /**
* @return the referred document * @return the referred document
*/ */
public String getReference() { public String getReference() {
return extractString("//ApplicableHeaderTradeAgreement/BuyerReference"); return extractString("//ApplicableHeaderTradeAgreement/BuyerReference");
} }
/** /**
* @return the sender's bank's BLZ code * @return the sender's bank's BLZ code
* @deprecated use BIC and IBAN instead of BLZ and KTO * @deprecated use BIC and IBAN instead of BLZ and KTO
*/ */
@Deprecated @Deprecated
public String getBLZ() { public String getBLZ() {
return extractString("//PayeeSpecifiedCreditorFinancialInstitution/GermanBankleitzahlID"); return extractString("//PayeeSpecifiedCreditorFinancialInstitution/GermanBankleitzahlID");
} }
/** /**
* @return the sender's account number * @return the sender's account number
* @deprecated use BIC and IBAN instead of BLZ and KTO * @deprecated use BIC and IBAN instead of BLZ and KTO
*/ */
@Deprecated @Deprecated
public String getKTO() { public String getKTO() {
return extractString("//PayeePartyCreditorFinancialAccount/ProprietaryID"); return extractString("//PayeePartyCreditorFinancialAccount/ProprietaryID");
} }
/** /**
* @return the sender's bank's BIC code * @return the sender's bank's BIC code
*/ */
public String getBIC() { public String getBIC() {
return extractString("//PayeeSpecifiedCreditorFinancialInstitution/BICID"); return extractString("//PayeeSpecifiedCreditorFinancialInstitution/BICID");
} }
/** /**
* @return the sender's bank name * @return the sender's bank name
*/ */
public String getBankName() { public String getBankName() {
return extractString("//PayeeSpecifiedCreditorFinancialInstitution/Name"); return extractString("//PayeeSpecifiedCreditorFinancialInstitution/Name");
} }
/** /**
* @return the sender's account IBAN code * @return the sender's account IBAN code
*/ */
public String getIBAN() { public String getIBAN() {
return extractString("//PayeePartyCreditorFinancialAccount/IBANID"); return extractString("//PayeePartyCreditorFinancialAccount/IBANID");
} }
public String getHolder() { public String getHolder() {
return extractString("//SellerTradeParty/Name"); return extractString("//SellerTradeParty/Name");
} }
/** /**
* @return the total payable amount * @return the total payable amount
*/ */
public String getAmount() { public String getAmount() {
String result = extractString("//SpecifiedTradeSettlementHeaderMonetarySummation/DuePayableAmount"); String result = extractString("//SpecifiedTradeSettlementHeaderMonetarySummation/DuePayableAmount");
if (result == null || result.isEmpty()) { if (result == null || result.isEmpty()) {
result = extractString("//SpecifiedTradeSettlementMonetarySummation/GrandTotalAmount"); result = extractString("//SpecifiedTradeSettlementMonetarySummation/GrandTotalAmount");
} }
return result; return result;
} }
/** /**
* @return when the payment is due * @return when the payment is due
*/ */
public String getDueDate() { public String getDueDate() {
return extractString("//SpecifiedTradePaymentTerms/DueDateDateTime/DateTimeString"); return extractString("//SpecifiedTradePaymentTerms/DueDateDateTime/DateTimeString");
} }
public HashMap<String, byte[]> getAdditionalData() { public HashMap<String, byte[]> getAdditionalData() {
return additionalXMLs; return additionalXMLs;
} }
/** /**
* get xmp metadata of the PDF, null if not available * get xmp metadata of the PDF, null if not available
* *
* @return string * @return string
*/ */
public String getXMP() { public String getXMP() {
return xmpString; return xmpString;
} }
/** /**
* @return if export found parseable ZUGFeRD data * @return if export found parseable ZUGFeRD data
*/ */
public boolean containsMeta() { public boolean containsMeta() {
return containsMeta; return containsMeta;
} }
/** /**
* @param meta raw XML to be set * @param meta raw XML to be set
* @throws IOException if raw can not be set * @throws IOException if raw can not be set
*/ */
public void setMeta(String meta) throws IOException { public void setMeta(String meta) throws IOException {
setRawXML(meta.getBytes()); setRawXML(meta.getBytes());
} }
/** /**
* @return raw XML of the invoice * @return raw XML of the invoice
*/ */
public String getMeta() { public String getMeta() {
if (rawXML == null) { if (rawXML == null) {
return null; return null;
} }
return new String(rawXML); return new String(rawXML);
} }
public int getVersion() throws Exception { public int getVersion() throws Exception {
if (!containsMeta) { if (!containsMeta) {
throw new Exception("Not yet parsed"); throw new Exception("Not yet parsed");
} }
if (getUTF8().contains("<rsm:CrossIndustryDocument")) { if (getUTF8().contains("<rsm:CrossIndustryDocument")) {
return 1; return 1;
} else if (getUTF8().contains("<rsm:CrossIndustryInvoice")) { } else if (getUTF8().contains("<rsm:CrossIndustryInvoice")) {
return 2; return 2;
} }
throw new Exception("ZUGFeRD version could not be determined"); throw new Exception("ZUGFeRD version could not be determined");
} }
/** /**
* @return return UTF8 XML (without BOM) of the invoice * @return return UTF8 XML (without BOM) of the invoice
*/ */
public String getUTF8() { public String getUTF8() {
if (rawXML == null) { if (rawXML == null) {
return null; return null;
} }
if (rawXML.length < 3) { if (rawXML.length < 3) {
return new String(rawXML); return new String(rawXML);
} }
byte[] bomlessData; byte[] bomlessData;
if ((rawXML[0] == (byte) 0xEF) if ((rawXML[0] == (byte) 0xEF)
&& (rawXML[1] == (byte) 0xBB) && (rawXML[1] == (byte) 0xBB)
&& (rawXML[2] == (byte) 0xBF)) { && (rawXML[2] == (byte) 0xBF)) {
// I don't like BOMs, lets remove it // I don't like BOMs, lets remove it
bomlessData = new byte[rawXML.length - 3]; bomlessData = new byte[rawXML.length - 3];
System.arraycopy(rawXML, 3, bomlessData, 0, System.arraycopy(rawXML, 3, bomlessData, 0,
rawXML.length - 3); rawXML.length - 3);
} else { } else {
bomlessData = rawXML; bomlessData = rawXML;
} }
return new String(bomlessData); return new String(bomlessData);
} }
/** /**
* Returns the raw XML data as extracted from the ZUGFeRD PDF file. * Returns the raw XML data as extracted from the ZUGFeRD PDF file.
* *
* @return the raw ZUGFeRD XML data * @return the raw ZUGFeRD XML data
*/ */
public byte[] getRawXML() { public byte[] getRawXML() {
return rawXML; return rawXML;
} }
/** /**
* will return true if the metadata (just extract-ed or set with setMeta) contains ZUGFeRD XML * will return true if the metadata (just extract-ed or set with setMeta) contains ZUGFeRD XML
* *
* @return true if the invoice contains ZUGFeRD XML * @return true if the invoice contains ZUGFeRD XML
*/ */
public boolean canParse() { public boolean canParse() {
// SpecifiedExchangedDocumentContext is in the schema, so a relatively good // SpecifiedExchangedDocumentContext is in the schema, so a relatively good
// indication if zugferd is present - better than just invoice // indication if zugferd is present - better than just invoice
String meta = getMeta(); String meta = getMeta();
return (meta != null) && (meta.length() > 0) && ((meta.contains("SpecifiedExchangedDocumentContext") //$NON-NLS-1$ return (meta != null) && (meta.length() > 0) && ((meta.contains("SpecifiedExchangedDocumentContext") //$NON-NLS-1$
/* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */)); /* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */));
} }
static String convertStreamToString(java.io.InputStream is) { static String convertStreamToString(java.io.InputStream is) {
// source https://stackoverflow.com/questions/309424/how-do-i-read-convert-an-inputstream-into-a-string-in-java referring to // source https://stackoverflow.com/questions/309424/how-do-i-read-convert-an-inputstream-into-a-string-in-java referring to
// https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks // https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks
Scanner s = new Scanner(is, "UTF-8").useDelimiter("\\A"); Scanner s = new Scanner(is, "UTF-8").useDelimiter("\\A");
return s.hasNext() ? s.next() : ""; return s.hasNext() ? s.next() : "";
} }
} }

View File

@@ -0,0 +1,71 @@
package org.mustangproject.ZUGFeRD;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.xpath.*;
import java.math.BigDecimal;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
public ZUGFeRDInvoiceImporter(String filename) {
super(filename);
}
public ZUGFeRD2PushProvider extractInvoice() {
String number="AB123";
ZUGFeRD2PushProvider zpp=new ZUGFeRD2PushProvider().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setOwnStreet("teststr").setOwnZIP("55232").setOwnLocation("teststadt").setOwnCountry("DE").setOwnTaxID("4711").setOwnVATID("0815").setRecipient(new Contact("Franz Müller", "0177123456", "fmueller@test.com", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number);
//.addItem(new Item(new Product("Testprodukt","","C62",new BigDecimal(0)),amount,new BigDecimal(1.0)))
zpp.setOwnOrganisationName(extractString("//SellerTradeParty/Name"));
XPathFactory xpathFact = XPathFactory.newInstance();
XPath xpath = xpathFact.newXPath();
try {
XPathExpression xpr = xpath.compile(
"//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]");
NodeList nodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (nodes.getLength() == 0) {
} else {
for (int i = 0; i < nodes.getLength(); i++) {
//nodes.item(i).getTextContent())) {
Node currentItemNode=nodes.item(i);
NodeList itemChilds=currentItemNode.getChildNodes();
String price="0";
for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) {
if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeAgreement")) {
NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes();
for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds.getLength(); tradeLineChildIndex++) {
if (tradeLineChilds.item(tradeLineChildIndex).getNodeName().equals("ram: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
}
}
}
}
}
}
// Logger.getLogger(ZUGFeRDInvoiceImporter.class.getName()).log(Level.INFO, "deb "+price);
zpp.addItem(new Item(new Product("Testprodukt","","C62",new BigDecimal(0)),new BigDecimal(price),new BigDecimal(1.0)));
}
}
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return zpp;
}
}

View File

@@ -0,0 +1,57 @@
/** **********************************************************************
*
* Copyright 2019 Jochen Staerk
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import junit.framework.TestCase;
import junit.framework.Test;
import junit.framework.TestSuite;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ZF2InvoiceImporterTest extends TestCase {
final String TARGET_PDF = "./target/testout-ZF2New.pdf";
public void testInvoiceImport() {
ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter(TARGET_PDF);
// Reading ZUGFeRD
assertEquals("Bei Spiel GmbH", zii.extractInvoice().getOwnOrganisationName());
assertEquals(3, zii.extractInvoice().getZFItems().length);
assertEquals("160.0000", zii.extractInvoice().getZFItems()[0].getPrice().toString());
}
}