Merge branch 'master' of github.com:ZUGFeRD/mustangproject

# Conflicts:
#	src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java
This commit is contained in:
Jochen Stärk
2019-04-11 17:06:09 +02:00
15 changed files with 521 additions and 711 deletions

View File

@@ -40,7 +40,7 @@
<github.global.server>github</github.global.server>
<additionalparam>-Xdoclint:none</additionalparam>
<!-- Skip error check for javadoc -->
<maven.compiler.compilerVersion>1.7</maven.compiler.compilerVersion>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
@@ -134,8 +134,8 @@
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
mvn clean compile assembly:single -->
<!-- or whatever version you use -->
<source>1.7</source>
<target>1.7</target>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>

View File

@@ -15,16 +15,23 @@
*/
package org.mustangproject.ZUGFeRD;
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
import java.math.BigDecimal;
/**
* @author AlexanderSchmidt
*/
public interface IZUGFeRDAllowanceCharge {
BigDecimal getTotalAmount();
String getReason();
BigDecimal getTaxPercent();
default String getCategoryCode() {
return TaxCategoryCodeTypeConstants.STANDARDRATE;
}
}

View File

@@ -19,9 +19,7 @@
package org.mustangproject.ZUGFeRD;
/**
* Mustangproject's ZUGFeRD implementation
* Neccessary interface for ZUGFeRD exporter
* Licensed under the APLv2
* Mustangproject's ZUGFeRD implementation Neccessary interface for ZUGFeRD exporter Licensed under the APLv2
*
* @author jstaerk
* @version 1.2.0
@@ -31,6 +29,16 @@ package org.mustangproject.ZUGFeRD;
public interface IZUGFeRDExportableContact {
/**
* customer identification assigned by the seller
*
* @return customer identification
*/
default String getID() {
return null;
}
/**
* First and last name of the recipient
*
@@ -38,6 +46,7 @@ public interface IZUGFeRDExportableContact {
*/
String getName();
/**
* Postal code of the recipient
*
@@ -45,6 +54,7 @@ public interface IZUGFeRDExportableContact {
*/
String getZIP();
/**
* VAT ID (Umsatzsteueridentifikationsnummer) of the contact
*
@@ -52,6 +62,7 @@ public interface IZUGFeRDExportableContact {
*/
String getVATID();
/**
* two-letter country code of the contact
*
@@ -59,6 +70,7 @@ public interface IZUGFeRDExportableContact {
*/
String getCountry();
/**
* Returns the city of the contact
*
@@ -66,6 +78,7 @@ public interface IZUGFeRDExportableContact {
*/
String getLocation();
/**
* Returns the street address (street+number) of the contact
*

View File

@@ -26,6 +26,8 @@ package org.mustangproject.ZUGFeRD;
* @author jstaerk
* */
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
import java.math.BigDecimal;
public interface IZUGFeRDExportableItem {
@@ -51,5 +53,8 @@ public interface IZUGFeRDExportableItem {
*/
BigDecimal getQuantity();
default String getCategoryCode() {
return TaxCategoryCodeTypeConstants.STANDARDRATE;
}
}

View File

@@ -27,55 +27,75 @@ package org.mustangproject.ZUGFeRD;
* */
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
import java.util.Date;
public interface IZUGFeRDExportableTransaction {
/**
*
*
* @return Code of Document
*/
default String getDocumentCode() {
return DocumentCodeTypeConstants.INVOICE;
}
/**
* Number, typically invoice number of the invoice
*
* @return invoice number
*/
String getNumber();
default String getNumber() {
return null;
}
/**
* the date when the invoice was created
*
* @return when the invoice was created
*/
Date getIssueDate();
default Date getIssueDate() {
return null;
}
/**
* this should be the full sender institution name, details, manager and tax registration.
* It is one of the few functions which may return null.
* e.g.
* this should be the full sender institution name, details, manager and tax registration. It is one of the few functions which may return null. e.g.
* <p/>
* Lieferant GmbH
* Lieferantenstraße 20
* 80333 München
* Deutschland
* Geschäftsführer: Hans Muster
* Handelsregisternummer: H A 123
* Lieferant GmbH Lieferantenstraße 20 80333 München Deutschland Geschäftsführer: Hans Muster Handelsregisternummer: H A 123
*
* @return null or full sender institution name, details, manager and tax registration
*/
String getOwnOrganisationFullPlaintextInfo();
default String getOwnOrganisationFullPlaintextInfo() {
return null;
}
/**
* when the invoice is to be paid
*
* @return when the invoice is to be paid
*/
Date getDueDate();
default Date getDueDate() {
return null;
}
IZUGFeRDAllowanceCharge[] getZFAllowances();
IZUGFeRDAllowanceCharge[] getZFCharges();
IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges();
IZUGFeRDExportableItem[] getZFItems();
/**
* the recipient
*
@@ -83,89 +103,136 @@ public interface IZUGFeRDExportableTransaction {
*/
IZUGFeRDExportableContact getRecipient();
/**
* BIC of the sender
*
* @return the BIC code of the recipient sender's bank
*/
String getOwnBIC();
default String getOwnBIC() {
return null;
}
/**
* BLZ of the sender
*
* @return the BLZ code of the recipient sender's bank
*/
String getOwnBLZ();
default String getOwnBLZ() {
return null;
}
/**
* Bank name of the sender
*
* @return the name of the sender's bank
*/
String getOwnBankName();
default String getOwnBankName() {
return null;
}
/**
* IBAN of the sender
*
* @return the IBAN of the invoice sender's bank account
*/
String getOwnIBAN();
default String getOwnIBAN() {
return null;
}
/**
* IBAN of the sender
*
* @return the Account Number of the invoice sender's bank account
*/
String getOwnKto();
default String getOwnKto() {
return null;
}
/**
* Tax ID (not VAT ID) of the sender
*
* @return Tax ID (not VAT ID) of the sender
*/
String getOwnTaxID();
default String getOwnTaxID() {
return null;
}
/**
* VAT ID (Umsatzsteueridentifikationsnummer) of the sender
*
* @return VAT ID (Umsatzsteueridentifikationsnummer) of the sender
*/
String getOwnVATID();
default String getOwnVATID() {
return null;
}
/**
* supplier identification assigned by the costumer
*
* @return the sender's identification
*/
default String getOwnForeignOrganisationID() {
return null;
}
/**
* own name
*
* @return the sender's organisation name
*/
String getOwnOrganisationName();
default String getOwnOrganisationName() {
return null;
}
/**
* own street address
*
* @return sender street address
*/
String getOwnStreet();
default String getOwnStreet() {
return null;
}
/**
* own street postal code
*
* @return sender postal code
*/
String getOwnZIP();
default String getOwnZIP() {
return null;
}
/**
* own city
*
* @return the invoice sender's city
*/
String getOwnLocation();
default String getOwnLocation() {
return null;
}
/**
* own two digit country code
*
* @return the invoice senders two character country iso code
*/
String getOwnCountry();
default String getOwnCountry() {
return null;
}
/**
* get delivery date
@@ -174,35 +241,44 @@ public interface IZUGFeRDExportableTransaction {
*/
Date getDeliveryDate();
/**
* get main invoice currency used on the invoice
*
* @return three character currency of this invoice
*/
String getCurrency();
default String getCurrency() {
return null;
}
/**
* get payment information text. e.g. Bank transfer
*
* @return payment information text
*/
String getOwnPaymentInfoText();
default String getOwnPaymentInfoText() {
return null;
}
/**
* get payment term descriptional text
* e.g. Bis zum 22.10.2015 ohne Abzug
* get payment term descriptional text e.g. Bis zum 22.10.2015 ohne Abzug
*
* @return get payment terms
*/
String getPaymentTermDescription();
default String getPaymentTermDescription() {
return null;
}
/**
* get reference document number
* typically used for Invoice Corrections
* Will be added as IncludedNote in comfort profile
* get reference document number typically used for Invoice Corrections Will be added as IncludedNote in comfort profile
*
* @return the ID of the document this document refers to
*/
String getReferenceNumber();
default String getReferenceNumber() {
return null;
}
}

View File

@@ -31,14 +31,17 @@ import java.math.BigDecimal;
*/
public class VATAmount {
public VATAmount(BigDecimal basis, BigDecimal calculated) {
public VATAmount(BigDecimal basis, BigDecimal calculated, String documentCode) {
super();
this.basis = basis;
this.calculated = calculated;
this.documentCode = documentCode;
}
BigDecimal basis, calculated;
String documentCode;
public BigDecimal getBasis() {
return basis;
}
@@ -55,12 +58,20 @@ public class VATAmount {
this.calculated = calculated;
}
public String getDocumentCode() {
return documentCode;
}
public void setDocumentCode(String documentCode) {
this.documentCode = documentCode;
}
public VATAmount add(VATAmount v) {
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()));
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.documentCode);
}
public VATAmount subtract(VATAmount v) {
return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()));
return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.documentCode);
}
}

View File

@@ -134,8 +134,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
res = res.add(amount.getCalculated());
}
return res;
}
@@ -162,16 +160,14 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
BigDecimal percent = currentItem.getProduct().getVATPercent();
LineCalc lc = new LineCalc(currentItem);
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount());
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), trans.getDocumentCode());
VATAmount current = hm.get(percent);
if (current == null) {
hm.put(percent, itemVATAmount);
} else {
hm.put(percent, current.add(itemVATAmount));
}
}
return hm;
}

View File

@@ -33,27 +33,21 @@ 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.w3c.dom.Document;
import org.w3c.dom.Node;
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.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
//root.setNamespace(Namespace.getNamespace("http://www.energystar.gov/manageBldgs/req"));
import java.util.*;
public class ZUGFeRDImporter {
/*
* call extract(importFilename). containsMeta() will return if ZUGFeRD data has
* been found, afterwards you can call getBIC(), getIBAN() etc.
*
*/
/**
* @var if metadata has been found
@@ -62,57 +56,31 @@ public class ZUGFeRDImporter {
/**
* @var the reference (i.e. invoice number) of the sender
*/
private String foreignReference;
private String BLZ;
private String BIC;
private String IBAN;
private String KTO;
private String holder;
private String amount;
private String dueDate;
private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
private HashMap<String, byte[]> additionalXMLs = new HashMap<>();
/**
* Raw XML form of the extracted data - may be directly obtained.
*/
private byte[] rawXML = null;
private String bankName;
private boolean amountFound;
private boolean extractAttempt = false;
private boolean parsed = false;
private String xmpString = null; // XMP metadata
private static final Logger LOG = Logger.getLogger(ZUGFeRDImporter.class.getName());
/**
* Extracts a ZUGFeRD invoice from a PDF document represented by a file name.
* Errors are just logged to STDOUT.
*
* @param pdfFilename the filename of the pdf
*/
public void extract(String pdfFilename) {
public ZUGFeRDImporter(String pdfFilename) {
try {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pdfFilename));
extractLowLevel(bis);
bis.close();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
throw new ZUGFeRDExportException(e);
}
}
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
// https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
/**
* get xmp metadata of the PDF, null if not available
*
* @return string
*/
public String getXMP() {
return xmpString;
public ZUGFeRDImporter(InputStream pdfStream) {
try {
extractLowLevel(pdfStream);
} catch (IOException e) {
e.printStackTrace();
throw new ZUGFeRDExportException(e);
}
}
/**
@@ -121,9 +89,7 @@ public class ZUGFeRDImporter {
*
* @param pdfStream a inputstream of a pdf file
*/
public void extractLowLevel(InputStream pdfStream) throws IOException {
PDEmbeddedFilesNameTreeNode etn;
extractAttempt = true;
private void extractLowLevel(InputStream pdfStream) throws IOException {
try (PDDocument doc = PDDocument.load(pdfStream)) {
// PDDocumentInformation info = doc.getDocumentInformation();
PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
@@ -131,7 +97,8 @@ public class ZUGFeRDImporter {
InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata();
xmpString = convertStreamToString(XMP);
etn = names.getEmbeddedFiles();
PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles();
if (etn == null) {
return;
}
@@ -188,352 +155,136 @@ public class ZUGFeRDImporter {
}
}
public HashMap<String, byte[]> getAdditionalData() {
return additionalXMLs;
private void prettyPrint(Document document) throws TransformerException {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = null;
try {
transformer = tf.newTransformer();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
}
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(document), new StreamResult(writer));
String output = writer.getBuffer().toString();//.replaceAll("\n|\r", "");
System.err.println(output);
}
/**
* needs to be called to be able to call the getters
*/
public void parse() {
DocumentBuilderFactory factory = null;
DocumentBuilder builder = null;
Document document = null;
private Document getDocument() throws ParserConfigurationException, IOException, SAXException, TransformerException {
DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
xmlFact.setNamespaceAware(false);
DocumentBuilder builder = xmlFact.newDocumentBuilder();
Document doc = builder.parse(new ByteArrayInputStream(rawXML));
//prettyPrint(doc);
return doc;
}
if (!extractAttempt) {
throw new RuntimeException("extract() or extractLowLevel() must be used before parsing.");
}
private String extractString(String xpathStr) {
if (!containsMeta) {
throw new RuntimeException("No suitable data/ZUGFeRD file could be found.");
throw new ZUGFeRDExportException("No suitable data/ZUGFeRD file could be found.");
}
factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // otherwise we can not act namespace independently, i.e. use
// document.getElementsByTagNameNS("*",...
String result;
try {
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException ex3) {
// TODO Auto-generated catch block
ex3.printStackTrace();
Document document = getDocument();
XPathFactory xpathFact = XPathFactory.newInstance();
XPath xpath = xpathFact.newXPath();
result = xpath.evaluate(xpathStr, document);
} catch (ParserConfigurationException e) {
e.printStackTrace();
throw new ZUGFeRDExportException(e);
} catch (IOException | SAXException | TransformerException | XPathExpressionException e) {
e.printStackTrace();
throw new ZUGFeRDExportException(e);
}
try {
InputStream bais = new ByteArrayInputStream(rawXML);
document = builder.parse(bais);
} catch (SAXException ex1) {
ex1.printStackTrace();
} catch (IOException ex2) {
ex2.printStackTrace();
}
NodeList ndList;
// rootNode = document.getDocumentElement();
// ApplicableSupplyChainTradeSettlement
ndList = document.getDocumentElement().getElementsByTagNameNS("*", "PaymentReference"); //$NON-NLS-1$
for (int bookingIndex = 0; bookingIndex < ndList.getLength(); bookingIndex++) {
Node booking = ndList.item(bookingIndex);
// if there is a attribute in the tag number:value
setForeignReference(booking.getTextContent());
}
/*
* ndList = document .getElementsByTagName("GermanBankleitzahlID");
* //$NON-NLS-1$
*
* for (int bookingIndex = 0; bookingIndex < ndList .getLength();
* bookingIndex++) { Node booking = ndList.item(bookingIndex); // if there is a
* attribute in the tag number:value setBIC(booking.getTextContent());
*
* }
*
* ndList = document.getElementsByTagName("ProprietaryID"); //$NON-NLS-1$
*
* for (int bookingIndex = 0; bookingIndex < ndList .getLength();
* bookingIndex++) { Node booking = ndList.item(bookingIndex); // if there is a
* attribute in the tag number:value setIBAN(booking.getTextContent());
*
* } <ram:PayeePartyCreditorFinancialAccount> <ram:IBANID>DE1234</ram:IBANID>
* </ram:PayeePartyCreditorFinancialAccount>
* <ram:PayeeSpecifiedCreditorFinancialInstitution>
* <ram:BICID>DE5656565</ram:BICID> <ram:Name>Commerzbank</ram:Name>
* </ram:PayeeSpecifiedCreditorFinancialInstitution>
*
*/
/***
* we should switch to xpath like this // Create XPathFactory object
* XPathFactory xpathFactory = XPathFactory.newInstance();
*
* // Create XPath object XPath xpath = xpathFactory.newXPath(); XPathExpression
* expr =
* xpath.compile("//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/[local-name()=\"ID\"]");
* //evaluate expression result on XML document ndList = (NodeList)
* expr.evaluate(doc, XPathConstants.NODESET);
*
*/
ndList = document.getElementsByTagNameNS("*", "PayeePartyCreditorFinancialAccount"); //$NON-NLS-1$
for (int bookingIndex = 0; bookingIndex < ndList.getLength(); bookingIndex++) {
Node booking = ndList.item(bookingIndex);
// there are many "name" elements, so get the one below
// SellerTradeParty
NodeList bookingDetails = booking.getChildNodes();
for (int detailIndex = 0; detailIndex < bookingDetails.getLength(); detailIndex++) {
Node detail = bookingDetails.item(detailIndex);
if ((detail.getLocalName() != null) && (detail.getLocalName().equals("IBANID"))) { //$NON-NLS-1$
setIBAN(detail.getTextContent());
}
if ((detail.getLocalName() != null) && (detail.getLocalName().equals("ProprietaryID"))) { //$NON-NLS-1$
setKTO(detail.getTextContent());
}
}
}
ndList = document.getElementsByTagNameNS("*", "PayeeSpecifiedCreditorFinancialInstitution");// ZF1 //$NON-NLS-1$
for (int bookingIndex = 0; bookingIndex < ndList.getLength(); bookingIndex++) {
Node booking = ndList.item(bookingIndex);
// there are many "name" elements, so get the one below
// SellerTradeParty
NodeList bookingDetails = booking.getChildNodes();
for (int detailIndex = 0; detailIndex < bookingDetails.getLength(); detailIndex++) {
Node detail = bookingDetails.item(detailIndex);
if ((detail.getLocalName() != null) && (detail.getLocalName().equals("BICID"))) { //$NON-NLS-1$
setBIC(detail.getTextContent());
}
if ((detail.getLocalName() != null) && (detail.getLocalName().equals("GermanBankleitzahlID"))) { //$NON-NLS-1$
setBLZ(detail.getTextContent());
}
if ((detail.getLocalName() != null) && (detail.getLocalName().equals("Name"))) { //$NON-NLS-1$
setBankName(detail.getTextContent());
}
}
}
ndList = document.getElementsByTagNameNS("*", "SellerTradeParty"); //$NON-NLS-1$
for (int bookingIndex = 0; bookingIndex < ndList.getLength(); bookingIndex++) {
Node booking = ndList.item(bookingIndex);
// there are many "name" elements, so get the one below
// SellerTradeParty
NodeList bookingDetails = booking.getChildNodes();
for (int detailIndex = 0; detailIndex < bookingDetails.getLength(); detailIndex++) {
Node detail = bookingDetails.item(detailIndex);
if ((detail.getLocalName() != null) && (detail.getLocalName().equals("Name"))) { //$NON-NLS-1$
setHolder(detail.getTextContent());
}
}
}
ndList = document.getElementsByTagNameNS("*", "DuePayableAmount"); //$NON-NLS-1$
for (int bookingIndex = 0; bookingIndex < ndList.getLength(); bookingIndex++) {
Node booking = ndList.item(bookingIndex);
// if there is a attribute in the tag number:value
amountFound = true;
setAmount(booking.getTextContent());
}
if (!amountFound) {
/*
* there is apparently no requirement to mention DuePayableAmount,, if it's not
* there, check for GrandTotalAmount
*/
ndList = document.getElementsByTagNameNS("*", "GrandTotalAmount"); //$NON-NLS-1$
for (int bookingIndex = 0; bookingIndex < ndList.getLength(); bookingIndex++) {
Node booking = ndList.item(bookingIndex);
// if there is a attribute in the tag number:value
amountFound = true;
setAmount(booking.getTextContent());
}
}
ndList = document.getElementsByTagNameNS("*", "SpecifiedTradePaymentTerms"); //$NON-NLS-1$
for (int bookingIndex = 0; bookingIndex < ndList.getLength(); bookingIndex++) {
Node booking = ndList.item(bookingIndex);
// there are many "name" elements, so get the one below
// SellerTradeParty
NodeList bookingDetails = booking.getChildNodes();
for (int detailIndex = 0; detailIndex < bookingDetails.getLength(); detailIndex++) {
Node detail = bookingDetails.item(detailIndex);
if ((detail.getLocalName() != null) && (detail.getLocalName().equals("DueDateDateTime"))) { //$NON-NLS-1$
setDueDate(detail.getTextContent().trim());
}
}
}
parsed = true;
}
/**
* @return if export found parseable ZUGFeRD data
*/
public boolean containsMeta() {
return containsMeta;
return result;
}
/**
* @return the reference (purpose) the sender specified for this invoice
*/
public String getForeignReference() {
if (!parsed) {
throw new RuntimeException("use extract() before requesting a value");
}
if (foreignReference == null) {
parse();
}
return foreignReference;
String result = extractString("//ApplicableHeaderTradeSettlement/PaymentReference");
if(result == null || result.isEmpty())
result = extractString("//ApplicableSupplyChainTradeSettlement/PaymentReference");
return result;
}
private void setForeignReference(String foreignReference) {
this.foreignReference = foreignReference;
/**
* @return the document code
*/
public String getDocumentCode() {
return extractString("//HeaderExchangedDocument/TypeCode");
}
/**
* @return the sender's bank's BLZ code
*/
public String getBLZ() {
if (!parsed) {
throw new RuntimeException("use extract() before requesting a value");
}
if (BLZ == null) {
parse();
}
return BLZ;
}
private void setBLZ(String blz) {
this.BLZ = blz;
return extractString("//PayeeSpecifiedCreditorFinancialInstitution/GermanBankleitzahlID");
}
/**
* @return the sender's bank's BIC code
*/
public String getBIC() {
if (!parsed) {
throw new RuntimeException("use extract() before requesting a value");
}
if (BIC == null) {
parse();
}
return BIC;
}
private void setBIC(String bic) {
this.BIC = bic;
}
private void setDueDate(String dueDate) {
this.dueDate = dueDate;
}
private void setBankName(String bankname) {
this.bankName = bankname;
return extractString("//PayeeSpecifiedCreditorFinancialInstitution/BICID");
}
/**
* @return the sender's IBAN
*/
public String getIBAN() {
if (!parsed) {
throw new RuntimeException("use extract() before requesting a value");
}
if (IBAN == null) {
parse();
}
return IBAN;
}
/**
* @return the sender's KTO
*/
public String getKTO() {
if (!parsed) {
throw new RuntimeException("use extract() before requesting a value");
}
if (KTO == null) {
parse();
}
return KTO;
}
/**
* @return the sender's bank name
* @return the sender's bankname
*/
public String getBankName() {
if (!parsed) {
throw new RuntimeException("use extract() before requesting a value");
}
if (bankName == null) {
parse();
}
return bankName;
return extractString("/CrossIndustryInvoice/SupplyChainTradeTransaction/ApplicableHeaderTradeSettlement/SpecifiedTradeSettlementPaymentMeans/PayeeSpecifiedCreditorFinancialInstitution/Name");
}
private void setIBAN(String IBAN) {
this.IBAN = IBAN;
public String getIBAN() {
return extractString("//PayeePartyCreditorFinancialAccount/IBANID");
}
private void setKTO(String KTO) {
this.KTO = KTO;
public String getKTO() {
return extractString("//PayeePartyCreditorFinancialAccount/ProprietaryID");
}
/**
* @return the name of the owner of the sender's bank account
*/
public String getHolder() {
if (rawXML == null) {
throw new RuntimeException("use extract() before requesting a value");
}
if (holder == null) {
parse();
}
return holder;
}
private void setHolder(String holder) {
this.holder = holder;
return extractString("//SellerTradeParty/Name");
}
/**
* @return the total payable amount
*/
public String getAmount() {
if (rawXML == null) {
throw new RuntimeException("use extract() before requesting a value");
}
if (amount == null) {
parse();
}
return amount;
String result = extractString("//SpecifiedTradeSettlementHeaderMonetarySummation/DuePayableAmount");
if(result == null || result.isEmpty())
result = extractString("//SpecifiedTradeSettlementMonetarySummation/GrandTotalAmount");
return result;
}
/**
* @return when the payment is due
*/
public String getDueDate() {
if (rawXML == null) {
throw new RuntimeException("use extract() before requesting a value");
}
if (dueDate == null) {
parse();
}
return dueDate;
return extractString("//SpecifiedTradePaymentTerms/DueDateDateTime/DateTimeString");
}
private void setAmount(String amount) {
this.amount = amount;
public HashMap<String, byte[]> getAdditionalData() {
return additionalXMLs;
}
/**
* get xmp metadata of the PDF, null if not available
*
* @return string
*/
public String getXMP() {
return xmpString;
}
/**
* @return if export found parseable ZUGFeRD data
*/
public boolean containsMeta() {
return containsMeta;
}
/**
@@ -604,4 +355,12 @@ public class ZUGFeRDImporter {
return (meta != null) && (meta.length() > 0) && ((meta.contains("SpecifiedExchangedDocumentContext") //$NON-NLS-1$
/* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */));
}
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
// https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks
Scanner s = new Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
}

View File

@@ -0,0 +1,23 @@
/** **********************************************************************
*
* Copyright 2019 ak on 09.04.19.
*
* 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;
public class ZUGFeRDImporterException extends RuntimeException {
}

View File

@@ -18,14 +18,65 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import org.mustangproject.ZUGFeRD.model.*;
import javax.xml.bind.JAXBElement;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import javax.xml.bind.JAXBElement;
import org.mustangproject.ZUGFeRD.model.AmountType;
import org.mustangproject.ZUGFeRD.model.CodeType;
import org.mustangproject.ZUGFeRD.model.CountryIDType;
import org.mustangproject.ZUGFeRD.model.CreditorFinancialAccountType;
import org.mustangproject.ZUGFeRD.model.CreditorFinancialInstitutionType;
import org.mustangproject.ZUGFeRD.model.CrossIndustryDocumentType;
import org.mustangproject.ZUGFeRD.model.DateTimeType;
import org.mustangproject.ZUGFeRD.model.DateTimeTypeConstants;
import org.mustangproject.ZUGFeRD.model.DocumentCodeType;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
import org.mustangproject.ZUGFeRD.model.DocumentContextParameterType;
import org.mustangproject.ZUGFeRD.model.DocumentContextParameterTypeConstants;
import org.mustangproject.ZUGFeRD.model.DocumentLineDocumentType;
import org.mustangproject.ZUGFeRD.model.ExchangedDocumentContextType;
import org.mustangproject.ZUGFeRD.model.ExchangedDocumentType;
import org.mustangproject.ZUGFeRD.model.IDType;
import org.mustangproject.ZUGFeRD.model.IndicatorType;
import org.mustangproject.ZUGFeRD.model.LogisticsServiceChargeType;
import org.mustangproject.ZUGFeRD.model.NoteType;
import org.mustangproject.ZUGFeRD.model.NoteTypeConstants;
import org.mustangproject.ZUGFeRD.model.ObjectFactory;
import org.mustangproject.ZUGFeRD.model.PaymentMeansCodeType;
import org.mustangproject.ZUGFeRD.model.PaymentMeansCodeTypeConstants;
import org.mustangproject.ZUGFeRD.model.PercentType;
import org.mustangproject.ZUGFeRD.model.QuantityType;
import org.mustangproject.ZUGFeRD.model.SupplyChainEventType;
import org.mustangproject.ZUGFeRD.model.SupplyChainTradeAgreementType;
import org.mustangproject.ZUGFeRD.model.SupplyChainTradeDeliveryType;
import org.mustangproject.ZUGFeRD.model.SupplyChainTradeLineItemType;
import org.mustangproject.ZUGFeRD.model.SupplyChainTradeSettlementType;
import org.mustangproject.ZUGFeRD.model.SupplyChainTradeTransactionType;
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeType;
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
import org.mustangproject.ZUGFeRD.model.TaxRegistrationType;
import org.mustangproject.ZUGFeRD.model.TaxRegistrationTypeConstants;
import org.mustangproject.ZUGFeRD.model.TaxTypeCodeType;
import org.mustangproject.ZUGFeRD.model.TaxTypeCodeTypeConstants;
import org.mustangproject.ZUGFeRD.model.TextType;
import org.mustangproject.ZUGFeRD.model.TradeAddressType;
import org.mustangproject.ZUGFeRD.model.TradeAllowanceChargeType;
import org.mustangproject.ZUGFeRD.model.TradePartyType;
import org.mustangproject.ZUGFeRD.model.TradePaymentTermsType;
import org.mustangproject.ZUGFeRD.model.TradePriceType;
import org.mustangproject.ZUGFeRD.model.TradeProductType;
import org.mustangproject.ZUGFeRD.model.TradeSettlementMonetarySummationType;
import org.mustangproject.ZUGFeRD.model.TradeSettlementPaymentMeansType;
import org.mustangproject.ZUGFeRD.model.TradeTaxType;
class ZUGFeRDTransactionModelConverter {
private static final SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd");
@@ -36,10 +87,11 @@ class ZUGFeRDTransactionModelConverter {
private boolean isTest;
private String currency = "EUR";
ZUGFeRDTransactionModelConverter(IZUGFeRDExportableTransaction trans) {
this.trans = trans;
totals = new Totals();
this.currency = trans.getCurrency() != null ? trans.getCurrency() : currency;
currency = trans.getCurrency() != null ? trans.getCurrency() : currency;
}
@@ -47,15 +99,15 @@ class ZUGFeRDTransactionModelConverter {
CrossIndustryDocumentType invoice = xmlFactory
.createCrossIndustryDocumentType();
invoice.setSpecifiedExchangedDocumentContext(this.getDocumentContext());
invoice.setHeaderExchangedDocument(this.getDocument());
invoice.setSpecifiedSupplyChainTradeTransaction(this
.getTradeTransaction());
invoice.setSpecifiedExchangedDocumentContext(getDocumentContext());
invoice.setHeaderExchangedDocument(getDocument());
invoice.setSpecifiedSupplyChainTradeTransaction(getTradeTransaction());
return xmlFactory
.createCrossIndustryDocument(invoice);
}
private ExchangedDocumentContextType getDocumentContext() {
ExchangedDocumentContextType context = xmlFactory
@@ -75,6 +127,7 @@ class ZUGFeRDTransactionModelConverter {
return context;
}
private ExchangedDocumentType getDocument() {
ExchangedDocumentType document = xmlFactory
@@ -94,7 +147,7 @@ class ZUGFeRDTransactionModelConverter {
document.setIssueDateTime(issueDateTime);
DocumentCodeType documentCodeType = xmlFactory.createDocumentCodeType();
documentCodeType.setValue(DocumentCodeTypeConstants.INVOICE);
documentCodeType.setValue(trans.getDocumentCode());
document.setTypeCode(documentCodeType);
TextType name = xmlFactory.createTextType();
@@ -113,7 +166,7 @@ class ZUGFeRDTransactionModelConverter {
document.getIncludedNote().add(regularInfo);
}
if (trans.getReferenceNumber() != null && !new String().equals(trans.getReferenceNumber())) {
if (trans.getReferenceNumber() != null && !"".equals(trans.getReferenceNumber())) {
NoteType referenceInfo = xmlFactory.createNoteType();
TextType referenceInfoContent = xmlFactory.createTextType();
referenceInfoContent.setValue("Ursprungsbeleg: " + trans.getReferenceNumber());
@@ -124,36 +177,44 @@ class ZUGFeRDTransactionModelConverter {
return document;
}
private SupplyChainTradeTransactionType getTradeTransaction() {
SupplyChainTradeTransactionType transaction = xmlFactory
.createSupplyChainTradeTransactionType();
transaction.getApplicableSupplyChainTradeAgreement().add(
this.getTradeAgreement());
transaction.setApplicableSupplyChainTradeDelivery(this
.getTradeDelivery());
transaction.setApplicableSupplyChainTradeSettlement(this
.getTradeSettlement());
getTradeAgreement());
transaction.setApplicableSupplyChainTradeDelivery(getTradeDelivery());
transaction.setApplicableSupplyChainTradeSettlement(getTradeSettlement());
transaction.getIncludedSupplyChainTradeLineItem().addAll(
this.getLineItems());
getLineItems());
return transaction;
}
private SupplyChainTradeAgreementType getTradeAgreement() {
SupplyChainTradeAgreementType tradeAgreement = xmlFactory
.createSupplyChainTradeAgreementType();
tradeAgreement.setBuyerTradeParty(this.getBuyer());
tradeAgreement.setSellerTradeParty(this.getSeller());
tradeAgreement.setBuyerTradeParty(getBuyer());
tradeAgreement.setSellerTradeParty(getSeller());
return tradeAgreement;
}
private TradePartyType getBuyer() {
TradePartyType buyerTradeParty = xmlFactory.createTradePartyType();
if (trans.getRecipient().getID() != null) {
IDType buyerID = xmlFactory.createIDType();
buyerID.setValue(trans.getRecipient().getID());
buyerTradeParty.getID().add(buyerID);
}
TextType buyerName = xmlFactory.createTextType();
buyerName.setValue(trans.getRecipient().getName());
buyerTradeParty.setName(buyerName);
@@ -189,9 +250,17 @@ class ZUGFeRDTransactionModelConverter {
return buyerTradeParty;
}
private TradePartyType getSeller() {
TradePartyType sellerTradeParty = xmlFactory.createTradePartyType();
if (trans.getOwnForeignOrganisationID() != null) {
IDType sellerID = xmlFactory.createIDType();
sellerID.setValue(trans.getOwnForeignOrganisationID());
sellerTradeParty.getID().add(sellerID);
}
TextType sellerName = xmlFactory.createTextType();
sellerName.setValue(trans.getOwnOrganisationName());
sellerTradeParty.setName(sellerName);
@@ -238,6 +307,7 @@ class ZUGFeRDTransactionModelConverter {
return sellerTradeParty;
}
private SupplyChainTradeDeliveryType getTradeDelivery() {
SupplyChainTradeDeliveryType tradeDelivery = xmlFactory
@@ -257,6 +327,7 @@ class ZUGFeRDTransactionModelConverter {
return tradeDelivery;
}
private SupplyChainTradeSettlementType getTradeSettlement() {
SupplyChainTradeSettlementType tradeSettlement = xmlFactory
.createSupplyChainTradeSettlementType();
@@ -270,29 +341,29 @@ class ZUGFeRDTransactionModelConverter {
tradeSettlement.setInvoiceCurrencyCode(currencyCode);
tradeSettlement.getSpecifiedTradeSettlementPaymentMeans().add(
this.getPaymentData());
tradeSettlement.getApplicableTradeTax().addAll(this.getTradeTax());
getPaymentData());
tradeSettlement.getApplicableTradeTax().addAll(getTradeTax());
tradeSettlement.getSpecifiedTradePaymentTerms().addAll(
this.getPaymentTerms());
getPaymentTerms());
if (trans.getZFAllowances() != null) {
tradeSettlement.getSpecifiedTradeAllowanceCharge().addAll(
this.getHeaderAllowances());
getHeaderAllowances());
}
if (trans.getZFLogisticsServiceCharges() != null) {
tradeSettlement.getSpecifiedLogisticsServiceCharge().addAll(
this.getHeaderLogisticsServiceCharges());
getHeaderLogisticsServiceCharges());
}
if (trans.getZFCharges() != null) {
tradeSettlement.getSpecifiedTradeAllowanceCharge().addAll(
this.getHeaderCharges());
getHeaderCharges());
}
tradeSettlement.setSpecifiedTradeSettlementMonetarySummation(this
.getMonetarySummation());
tradeSettlement.setSpecifiedTradeSettlementMonetarySummation(getMonetarySummation());
return tradeSettlement;
}
private TradeSettlementPaymentMeansType getPaymentData() {
TradeSettlementPaymentMeansType paymentData = xmlFactory
.createTradeSettlementPaymentMeansType();
@@ -335,11 +406,11 @@ class ZUGFeRDTransactionModelConverter {
return paymentData;
}
private Collection<TradeTaxType> getTradeTax() {
List<TradeTaxType> tradeTaxTypes = new ArrayList<TradeTaxType>();
HashMap<BigDecimal, VATAmount> VATPercentAmountMap = this
.getVATPercentAmountMap();
private Collection<TradeTaxType> getTradeTax() {
List<TradeTaxType> tradeTaxTypes = new ArrayList<>();
HashMap<BigDecimal, VATAmount> VATPercentAmountMap = this.getVATPercentAmountMap();
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
@@ -347,9 +418,9 @@ class ZUGFeRDTransactionModelConverter {
taxTypeCode.setValue(TaxTypeCodeTypeConstants.SALESTAX);
tradeTax.setTypeCode(taxTypeCode);
TaxCategoryCodeType taxCategoryCode = xmlFactory
.createTaxCategoryCodeType();
taxCategoryCode.setValue(TaxCategoryCodeTypeConstants.STANDARDRATE);
TaxCategoryCodeType taxCategoryCode = xmlFactory.createTaxCategoryCodeType();
VATAmount vatAmount = VATPercentAmountMap.get(currentTaxPercent);
taxCategoryCode.setValue(vatAmount.getDocumentCode());
tradeTax.setCategoryCode(taxCategoryCode);
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
@@ -360,8 +431,7 @@ class ZUGFeRDTransactionModelConverter {
AmountType calculatedTaxAmount = xmlFactory.createAmountType();
calculatedTaxAmount.setCurrencyID(currency);
calculatedTaxAmount
.setValue(currencyFormat(amount.getCalculated()));
calculatedTaxAmount.setValue(currencyFormat(amount.getCalculated()));
tradeTax.getCalculatedAmount().add(calculatedTaxAmount);
AmountType basisTaxAmount = xmlFactory.createAmountType();
@@ -375,14 +445,13 @@ class ZUGFeRDTransactionModelConverter {
return tradeTaxTypes;
}
private Collection<TradeAllowanceChargeType> getHeaderAllowances() {
List<TradeAllowanceChargeType> headerAllowances = new ArrayList<TradeAllowanceChargeType>();
List<TradeAllowanceChargeType> headerAllowances = new ArrayList<>();
for (IZUGFeRDAllowanceCharge iAllowance : trans.getZFAllowances()) {
TradeAllowanceChargeType allowance = xmlFactory
.createTradeAllowanceChargeType();
TradeAllowanceChargeType allowance = xmlFactory.createTradeAllowanceChargeType();
IndicatorType chargeIndicator = xmlFactory.createIndicatorType();
chargeIndicator.setIndicator(false);
allowance.setChargeIndicator(chargeIndicator);
@@ -397,7 +466,6 @@ class ZUGFeRDTransactionModelConverter {
allowance.setReason(reason);
TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
PercentType vatPercent = xmlFactory.createPercentType();
vatPercent.setValue(currencyFormat(iAllowance.getTaxPercent()));
tradeTax.setApplicablePercent(vatPercent);
@@ -409,9 +477,8 @@ class ZUGFeRDTransactionModelConverter {
* basisAmount.setValue(amount.getBasis());
* allowance.setBasisAmount(basisAmount);
*/
TaxCategoryCodeType taxType = xmlFactory
.createTaxCategoryCodeType();
taxType.setValue(TaxCategoryCodeTypeConstants.STANDARDRATE);
TaxCategoryCodeType taxType = xmlFactory.createTaxCategoryCodeType();
taxType.setValue(iAllowance.getCategoryCode());
tradeTax.setCategoryCode(taxType);
TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
@@ -420,20 +487,18 @@ class ZUGFeRDTransactionModelConverter {
allowance.getCategoryTradeTax().add(tradeTax);
headerAllowances.add(allowance);
}
return headerAllowances;
}
private Collection<TradeAllowanceChargeType> getHeaderCharges() {
List<TradeAllowanceChargeType> headerCharges = new ArrayList<TradeAllowanceChargeType>();
List<TradeAllowanceChargeType> headerCharges = new ArrayList<>();
for (IZUGFeRDAllowanceCharge iCharge : trans.getZFCharges()) {
TradeAllowanceChargeType charge = xmlFactory
.createTradeAllowanceChargeType();
TradeAllowanceChargeType charge = xmlFactory.createTradeAllowanceChargeType();
IndicatorType chargeIndicator = xmlFactory.createIndicatorType();
chargeIndicator.setIndicator(true);
charge.setChargeIndicator(chargeIndicator);
@@ -448,7 +513,6 @@ class ZUGFeRDTransactionModelConverter {
charge.setReason(reason);
TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
PercentType vatPercent = xmlFactory.createPercentType();
vatPercent.setValue(currencyFormat(iCharge.getTaxPercent()));
tradeTax.setApplicablePercent(vatPercent);
@@ -460,9 +524,8 @@ class ZUGFeRDTransactionModelConverter {
* basisAmount.setValue(amount.getBasis());
* allowance.setBasisAmount(basisAmount);
*/
TaxCategoryCodeType taxType = xmlFactory
.createTaxCategoryCodeType();
taxType.setValue(TaxCategoryCodeTypeConstants.STANDARDRATE);
TaxCategoryCodeType taxType = xmlFactory.createTaxCategoryCodeType();
taxType.setValue(iCharge.getCategoryCode());
tradeTax.setCategoryCode(taxType);
TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
@@ -477,19 +540,17 @@ class ZUGFeRDTransactionModelConverter {
return headerCharges;
}
private Collection<LogisticsServiceChargeType> getHeaderLogisticsServiceCharges() {
List<LogisticsServiceChargeType> headerServiceCharge = new ArrayList<LogisticsServiceChargeType>();
List<LogisticsServiceChargeType> headerServiceCharge = new ArrayList<>();
for (IZUGFeRDAllowanceCharge iServiceCharge : trans
.getZFLogisticsServiceCharges()) {
for (IZUGFeRDAllowanceCharge iServiceCharge : trans.getZFLogisticsServiceCharges()) {
LogisticsServiceChargeType serviceCharge = xmlFactory
.createLogisticsServiceChargeType();
LogisticsServiceChargeType serviceCharge = xmlFactory.createLogisticsServiceChargeType();
AmountType actualAmount = xmlFactory.createAmountType();
actualAmount.setCurrencyID(currency);
actualAmount.setValue(currencyFormat(iServiceCharge
.getTotalAmount()));
actualAmount.setValue(currencyFormat(iServiceCharge.getTotalAmount()));
serviceCharge.getAppliedAmount().add(actualAmount);
TextType reason = xmlFactory.createTextType();
@@ -509,9 +570,8 @@ class ZUGFeRDTransactionModelConverter {
* basisAmount.setValue(amount.getBasis());
* allowance.setBasisAmount(basisAmount);
*/
TaxCategoryCodeType taxType = xmlFactory
.createTaxCategoryCodeType();
taxType.setValue(TaxCategoryCodeTypeConstants.STANDARDRATE);
TaxCategoryCodeType taxType = xmlFactory.createTaxCategoryCodeType();
taxType.setValue(iServiceCharge.getCategoryCode());
tradeTax.setCategoryCode(taxType);
TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
@@ -526,8 +586,9 @@ class ZUGFeRDTransactionModelConverter {
return headerServiceCharge;
}
private Collection<TradePaymentTermsType> getPaymentTerms() {
List<TradePaymentTermsType> paymentTerms = new ArrayList<TradePaymentTermsType>();
List<TradePaymentTermsType> paymentTerms = new ArrayList<>();
TradePaymentTermsType paymentTerm = xmlFactory
.createTradePaymentTermsType();
@@ -553,6 +614,7 @@ class ZUGFeRDTransactionModelConverter {
return paymentTerms;
}
private TradeSettlementMonetarySummationType getMonetarySummation() {
TradeSettlementMonetarySummationType monetarySummation = xmlFactory
.createTradeSettlementMonetarySummationType();
@@ -630,9 +692,10 @@ class ZUGFeRDTransactionModelConverter {
return monetarySummation;
}
private Collection<SupplyChainTradeLineItemType> getLineItems() {
ArrayList<SupplyChainTradeLineItemType> lineItems = new ArrayList<SupplyChainTradeLineItemType>();
ArrayList<SupplyChainTradeLineItemType> lineItems = new ArrayList<>();
int lineID = 0;
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
lineID++;
@@ -734,9 +797,8 @@ class ZUGFeRDTransactionModelConverter {
.createSupplyChainTradeSettlementType();
TradeTaxType tradeTax = xmlFactory.createTradeTaxType();
TaxCategoryCodeType taxCategoryCode = xmlFactory
.createTaxCategoryCodeType();
taxCategoryCode.setValue(TaxCategoryCodeTypeConstants.STANDARDRATE);
TaxCategoryCodeType taxCategoryCode = xmlFactory.createTaxCategoryCodeType();
taxCategoryCode.setValue(currentItem.getCategoryCode());
tradeTax.setCategoryCode(taxCategoryCode);
TaxTypeCodeType taxCode = xmlFactory.createTaxTypeCodeType();
@@ -777,22 +839,27 @@ class ZUGFeRDTransactionModelConverter {
return lineItems;
}
private BigDecimal vatFormat(BigDecimal value) {
return nDigitFormat(value, 2);
}
private BigDecimal currencyFormat(BigDecimal value) {
return nDigitFormat(value, 2);
}
private BigDecimal priceFormat(BigDecimal value) {
return nDigitFormat(value, 4);
}
private BigDecimal quantityFormat(BigDecimal value) {
return nDigitFormat(value, 4);
}
private BigDecimal nDigitFormat(BigDecimal value, int scale) {
/*
* I needed 123,45, locale independent.I tried
@@ -837,11 +904,10 @@ class ZUGFeRDTransactionModelConverter {
}
/**
* which taxes have been used with which amounts in this transaction, empty
* for no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable to
* 19% VAT (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT)
* 190 Eur
* which taxes have been used with which amounts in this transaction, empty for no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable to 19% VAT
* (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT) 190 Eur
*
* @return HashMap<BigDecimal, VATAmount> which taxes have been used with which amounts
*/
@@ -849,15 +915,14 @@ class ZUGFeRDTransactionModelConverter {
return getVATPercentAmountMap(false);
}
private HashMap<BigDecimal, VATAmount> getVATPercentAmountMap(
Boolean itemOnly) {
HashMap<BigDecimal, VATAmount> hm = new HashMap<BigDecimal, VATAmount>();
private HashMap<BigDecimal, VATAmount> getVATPercentAmountMap(Boolean itemOnly) {
HashMap<BigDecimal, VATAmount> hm = new HashMap<>();
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
BigDecimal percent = currentItem.getProduct().getVATPercent();
LineCalc lc = new LineCalc(currentItem);
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(),
lc.getItemTotalVATAmount());
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), trans.getDocumentCode());
VATAmount current = hm.get(percent);
if (current == null) {
hm.put(percent, itemVATAmount);
@@ -869,13 +934,12 @@ class ZUGFeRDTransactionModelConverter {
return hm;
}
if (trans.getZFAllowances() != null) {
for (IZUGFeRDAllowanceCharge headerAllowance : trans
.getZFAllowances()) {
for (IZUGFeRDAllowanceCharge headerAllowance : trans.getZFAllowances()) {
BigDecimal percent = headerAllowance.getTaxPercent();
VATAmount itemVATAmount = new VATAmount(
headerAllowance.getTotalAmount(), headerAllowance
.getTotalAmount().multiply(percent)
.divide(new BigDecimal(100)));
.divide(new BigDecimal(100)), trans.getDocumentCode());
VATAmount current = hm.get(percent);
if (current == null) {
hm.put(percent, itemVATAmount);
@@ -892,7 +956,7 @@ class ZUGFeRDTransactionModelConverter {
VATAmount itemVATAmount = new VATAmount(
logisticsServiceCharge.getTotalAmount(),
logisticsServiceCharge.getTotalAmount()
.multiply(percent).divide(new BigDecimal(100)));
.multiply(percent).divide(new BigDecimal(100)), trans.getDocumentCode());
VATAmount current = hm.get(percent);
if (current == null) {
hm.put(percent, itemVATAmount);
@@ -907,7 +971,7 @@ class ZUGFeRDTransactionModelConverter {
BigDecimal percent = charge.getTaxPercent();
VATAmount itemVATAmount = new VATAmount(
charge.getTotalAmount(), charge.getTotalAmount()
.multiply(percent).divide(new BigDecimal(100)));
.multiply(percent).divide(new BigDecimal(100)), trans.getDocumentCode());
VATAmount current = hm.get(percent);
if (current == null) {
hm.put(percent, itemVATAmount);
@@ -920,6 +984,7 @@ class ZUGFeRDTransactionModelConverter {
return hm;
}
ZUGFeRDTransactionModelConverter withTest(boolean isTest) {
this.isTest = isTest;
return this;
@@ -932,6 +997,7 @@ class ZUGFeRDTransactionModelConverter {
private BigDecimal itemTotalVATAmount;
private BigDecimal itemNetAmount;
public LineCalc(IZUGFeRDExportableItem currentItem) {
BigDecimal totalAllowance = BigDecimal.ZERO;
BigDecimal totalCharge = BigDecimal.ZERO;
@@ -974,14 +1040,17 @@ class ZUGFeRDTransactionModelConverter {
BigDecimal.ROUND_HALF_UP);
}
public BigDecimal getItemTotalNetAmount() {
return itemTotalNetAmount;
}
public BigDecimal getItemTotalVATAmount() {
return itemTotalVATAmount;
}
public BigDecimal getItemNetAmount() {
return itemNetAmount;
}
@@ -994,6 +1063,7 @@ class ZUGFeRDTransactionModelConverter {
private BigDecimal lineTotalAmount;
private BigDecimal totalTaxAmount;
public Totals() {
BigDecimal res = BigDecimal.ZERO;
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
@@ -1001,7 +1071,7 @@ class ZUGFeRDTransactionModelConverter {
res = res.add(lc.getItemTotalNetAmount());
}
// Set line total
this.lineTotalAmount = res;
lineTotalAmount = res;
if (trans.getZFAllowances() != null) {
for (IZUGFeRDAllowanceCharge headerAllowance : trans
@@ -1024,33 +1094,36 @@ class ZUGFeRDTransactionModelConverter {
}
// Set total net amount
this.totalNetAmount = res;
totalNetAmount = res;
HashMap<BigDecimal, VATAmount> VATPercentAmountMap = getVATPercentAmountMap();
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
HashMap<BigDecimal, VATAmount> vatAmountHashMap = getVATPercentAmountMap();
for (VATAmount amount : vatAmountHashMap.values()) {
res = res.add(amount.getCalculated());
}
// Set total gross amount
this.totalGrossAmount = res;
totalGrossAmount = res;
this.totalTaxAmount = this.totalGrossAmount
.subtract(this.totalNetAmount);
totalTaxAmount = totalGrossAmount
.subtract(totalNetAmount);
}
public BigDecimal getTotalNet() {
return totalNetAmount;
}
public BigDecimal getTotalGross() {
return totalGrossAmount;
}
public BigDecimal getLineTotal() {
return lineTotalAmount;
}
public BigDecimal getTaxTotal() {
return totalTaxAmount;
}

View File

@@ -49,9 +49,8 @@ public class FileChecker {
if ((!isPDF) && (!thisRun.shallIgnoreFileExt())) {
return false;
}
ZUGFeRDImporter zi = new ZUGFeRDImporter();
ZUGFeRDImporter zi = new ZUGFeRDImporter(filename);
try {
zi.extract(filename);
if (zi.canParse()) {
thisRun.incZUGFeRDCount();
return true;

View File

@@ -406,8 +406,7 @@ public class Toecount {
ensureFileNotExists(xmlName);
// All params are good! continue...
ZUGFeRDImporter zi = new ZUGFeRDImporter();
zi.extract(pdfName);
ZUGFeRDImporter zi = new ZUGFeRDImporter(pdfName);
byte[] XMLContent = zi.getRawXML();
if (XMLContent == null) {
System.err.println("No ZUGFeRD XML found in PDF file");

View File

@@ -55,14 +55,12 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
// the writing part
try {
InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporter zea1 = new ZUGFeRDExporterFromA1Factory().setProducer("My Application").setCreator("Test").setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931)
.load(SOURCE_PDF);
final byte[] UTF8ByteOrderMark = new byte[]{(byte) 0xef, (byte) 0xbb,
(byte) 0xbf};
final byte[] UTF8ByteOrderMark = new byte[]{(byte) 0xef, (byte) 0xbb, (byte) 0xbf};
/* we have much more information than just in the basic profile (comfort or extended) but it's perfectly valid to provide more information, just not less. */
String ownZUGFeRDXML = new String(UTF8ByteOrderMark) + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<rsm:CrossIndustryInvoice xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:rsm=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100\" xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100\" xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100\">\n" +
@@ -267,41 +265,20 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter();
zi.extract(TARGET_PDF);
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
// Reading ZUGFeRD
String amount = null;
String bic = null;
String blz = null;
String iban = null;
String kto = null;
String holder = null;
String ref = null;
if (zi.canParse()) {
zi.parse();
amount = zi.getAmount();
blz = zi.getBLZ();
bic = zi.getBIC();
iban = zi.getIBAN();
kto = zi.getKTO();
holder = zi.getHolder();
ref = zi.getForeignReference();
}
assertEquals(amount, "571.04");
assertEquals(blz, "41441604");
assertEquals(bic, "COBADEFFXXX");
assertEquals(iban, "DE88 2008 0000 0970 3757 00");
assertEquals(kto, "44421800");
assertEquals(holder, "Bei Spiel GmbH");
assertEquals(ref, "RE-20171118/506");
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBLZ(), "41441604");
assertEquals(zi.getBIC(), "COBADEFFXXX");
assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00");
assertEquals(zi.getKTO(), "44421800");
assertEquals(zi.getHolder(), "Bei Spiel GmbH");
assertEquals(zi.getForeignReference(), "RE-20171118/506");
}
/**
@@ -318,8 +295,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
// the writing part
try {
InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporter zea1 = new ZUGFeRDExporterFromA1Factory().setProducer("My Application").setCreator("Test").setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.BASIC)
.load(SOURCE_PDF);
@@ -469,41 +445,20 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>BASIC</zf:ConformanceLevel>") == -1);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter();
zi.extract(TARGET_PDF);
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
// Reading ZUGFeRD
String amount = null;
String bic = null;
String blz = null;
String iban = null;
String kto = null;
String holder = null;
String ref = null;
if (zi.canParse()) {
zi.parse();
amount = zi.getAmount();
bic = zi.getBIC();
blz = zi.getBLZ();
iban = zi.getIBAN();
kto = zi.getKTO();
holder = zi.getHolder();
ref = zi.getForeignReference();
}
assertEquals(amount, "571.04");
assertEquals(bic, "COBADEFFXXX");
assertEquals(blz, "41441604");
assertEquals(iban, "DE88 2008 0000 0970 3757 00");
assertEquals(kto, "44421800");
assertEquals(holder, "Bei Spiel GmbH");
assertEquals(ref, "RE-20170509/505");
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), "COBADEFFXXX");
assertEquals(zi.getBLZ(), "41441604");
assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00");
assertEquals(zi.getKTO(), "44421800");
assertEquals(zi.getHolder(), "Bei Spiel GmbH");
assertEquals(zi.getForeignReference(), "RE-20170509/505");
}
}

View File

@@ -336,40 +336,19 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
*/
public void testAImport() throws IOException {
ZUGFeRDImporter zi = new ZUGFeRDImporter();
zi.extractLowLevel(this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505.pdf"));
InputStream inputStream = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505.pdf");
ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream);
// Reading ZUGFeRD
String amount = null;
String bic = null;
String blz = null;
String iban = null;
String kto = null;
String holder = null;
String ref = null;
String dueDate = null;
if (zi.canParse()) {
zi.parse();
amount = zi.getAmount();
bic = zi.getBIC();
blz = zi.getBLZ();
iban = zi.getIBAN();
kto = zi.getKTO();
holder = zi.getHolder();
dueDate = zi.getDueDate();
ref = zi.getForeignReference();
}
assertEquals(amount, "571.04");
assertEquals(bic, getOwnBIC());
assertEquals(blz, getOwnBLZ());
assertEquals(iban, getOwnIBAN());
assertEquals(kto, getOwnKto());
assertEquals(holder, getOwnOrganisationName());
assertEquals(dueDate, "20170530");
assertEquals(ref, getNumber());
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getOwnBIC());
assertEquals(zi.getBLZ(), getOwnBLZ());
assertEquals(zi.getIBAN(), getOwnIBAN());
assertEquals(zi.getKTO(), getOwnKto());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getDueDate(), "20170530");
assertEquals(zi.getForeignReference(), getNumber());
assertEquals(zi.getDocumentCode(), "380");
}
@@ -401,37 +380,16 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter();
zi.extract(TARGET_PDF);
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
// Reading ZUGFeRD
String amount = null;
String bic = null;
String blz = null;
String iban = null;
String kto = null;
String holder = null;
String ref = null;
if (zi.canParse()) {
zi.parse();
amount = zi.getAmount();
bic = zi.getBIC();
blz = zi.getBLZ();
iban = zi.getIBAN();
kto = zi.getKTO();
holder = zi.getHolder();
ref = zi.getForeignReference();
}
assertEquals(amount, "571.04");
assertEquals(bic, getOwnBIC());
assertEquals(blz, getOwnBLZ());
assertEquals(iban, getOwnIBAN());
assertEquals(kto, getOwnKto());
assertEquals(holder, getOwnOrganisationName());
assertEquals(ref, getNumber());
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getOwnBIC());
assertEquals(zi.getBLZ(), getOwnBLZ());
assertEquals(zi.getIBAN(), getOwnIBAN());
assertEquals(zi.getKTO(), getOwnKto());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
}
}

View File

@@ -346,52 +346,24 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta
*/
public void testAImport() throws IOException {
ZUGFeRDImporter zi = new ZUGFeRDImporter();
try (InputStream inputStream = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505.pdf")) {
zi.extractLowLevel(inputStream);
}
InputStream inputStream = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505.pdf");
ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream);
// Reading ZUGFeRD
String amount = null;
String blz = null;
String bic = null;
String iban = null;
String kto = null;
String holder = null;
String ref = null;
if (zi.canParse()) {
zi.parse();
amount = zi.getAmount();
blz = zi.getBLZ();
bic = zi.getBIC();
iban = zi.getIBAN();
kto = zi.getKTO();
holder = zi.getHolder();
ref = zi.getForeignReference();
}
// this resembles the data written in MustangReaderWriterCustomXMLTest
assertEquals(amount, "571.04");
assertEquals(blz, "41441604");
assertEquals(bic, "COBADEFFXXX");
assertEquals(iban, "DE88 2008 0000 0970 3757 00");
assertEquals(kto, "44421800");
assertEquals(holder, "Bei Spiel GmbH");
assertEquals(ref, "RE-20170509/505");
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBLZ(), getOwnBLZ());
assertEquals(zi.getBIC(), getOwnBIC());
assertEquals(zi.getIBAN(), getOwnIBAN());
assertEquals(zi.getKTO(), getOwnKto());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), "RE-20170509/505");
}
public void testForeignImport() throws IOException {
ZUGFeRDImporter zi = new ZUGFeRDImporter();
InputStream inputStream = this.getClass().getResourceAsStream("/zugferd_invoice.pdf");
ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream);
try (InputStream inputStream = this.getClass()
.getResourceAsStream("/zugferd_invoice.pdf")) {
zi.extractLowLevel(inputStream);
}
// Reading ZUGFeRD
String amount = zi.getAmount();
assertEquals("<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n" +
@@ -523,35 +495,17 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter();
zi.extract(TARGET_PDF);
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
// Reading ZUGFeRD
String amount = null;
String bic = null;
String iban = null;
String kto = null;
String holder = null;
String ref = null;
if (zi.canParse()) {
zi.parse();
amount = zi.getAmount();
bic = zi.getBIC();
iban = zi.getIBAN();
kto = zi.getKTO();
holder = zi.getHolder();
ref = zi.getForeignReference();
}
assertEquals(amount, "571.04");
assertEquals(bic, getOwnBIC());
assertEquals(iban, getOwnIBAN());
assertEquals(kto, getOwnKto());
assertEquals(holder, getOwnOrganisationName());
assertEquals(ref, getNumber());
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getOwnBIC());
assertEquals(zi.getIBAN(), getOwnIBAN());
assertEquals(zi.getKTO(), getOwnKto());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
}
public void testFXExport() throws Exception {
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506fx.pdf";
@@ -578,33 +532,15 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter();
zi.extract(TARGET_PDF);
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
// Reading ZUGFeRD
String amount = null;
String bic = null;
String iban = null;
String kto = null;
String holder = null;
String ref = null;
if (zi.canParse()) {
zi.parse();
amount = zi.getAmount();
bic = zi.getBIC();
iban = zi.getIBAN();
kto = zi.getKTO();
holder = zi.getHolder();
ref = zi.getForeignReference();
}
assertEquals(amount, "571.04");
assertEquals(bic, getOwnBIC());
assertEquals(iban, getOwnIBAN());
assertEquals(kto, getOwnKto());
assertEquals(holder, getOwnOrganisationName());
assertEquals(ref, getNumber());
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getOwnBIC());
assertEquals(zi.getIBAN(), getOwnIBAN());
assertEquals(zi.getKTO(), getOwnKto());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
}
/**