Merge branch 'temp_for_upstream_merge_of_PR4_08_2019'
This is necessary because the automatic rebase of pull request https://github.com/seeburger-ag/PDFA3/pull/4 did not work. Merge is done via command line as suggested by GitHub.
This commit is contained in:
17
History.md
17
History.md
@@ -1,10 +1,27 @@
|
||||
1.7.3
|
||||
=====
|
||||
2019-08-01
|
||||
|
||||
- #105 does not build in windows
|
||||
- #99 BOMs confuse parser
|
||||
- updated javadoc
|
||||
- fixed #104 nullpointerex when specifying no parameter
|
||||
- PR #112 complete profile options for v1
|
||||
- access to TotalPrepaidAmount in ZF v1 #118
|
||||
- have unit tests for nDigitFormat #23
|
||||
|
||||
|
||||
1.7.2
|
||||
=====
|
||||
2019-07-08
|
||||
|
||||
Support BuyerReference (r+w), as well as SpecifiedLegalOrganization (w) and DefinedTradeContact (w)
|
||||
use dom4j to format output xml document
|
||||
corrected some exception logging glitches
|
||||
upgrade PDFBox to 2.0.15+
|
||||
extraction to use proper filename instead of alias #98
|
||||
NullPointerException in ZUGFeRDImporter.extractLowLevel #96
|
||||
Removed Bankleitzahl from ZF2
|
||||
|
||||
|
||||
1.7.1
|
||||
|
||||
27
pom.xml
27
pom.xml
@@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.mustangproject.ZUGFeRD</groupId>
|
||||
<artifactId>mustang</artifactId>
|
||||
<version>1.7.2-SNAPSHOT</version>
|
||||
<version>1.7.4-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>Mustang</name>
|
||||
<description>The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs
|
||||
@@ -14,7 +13,7 @@
|
||||
<connection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</developerConnection>
|
||||
<url>https://github.com/ZUGFeRD/mustangproject</url>
|
||||
<tag>mustang-1.5.2</tag>
|
||||
<tag>mustang-1.7.3</tag>
|
||||
</scm>
|
||||
<repositories>
|
||||
<repository><!-- for jargs -->
|
||||
@@ -66,15 +65,26 @@
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<version>2.2.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.2.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>activation</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>preflight</artifactId>
|
||||
<version>2.0.12</version>
|
||||
<version>[2.0.15,)</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox</artifactId>
|
||||
<version>2.0.12</version>
|
||||
<version>[2.0.15,)</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dom4j</groupId>
|
||||
@@ -203,8 +213,7 @@
|
||||
<version>2.4.3</version>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>org.mustangproject.toecount.Toecount</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
@@ -279,7 +288,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||
<version>2.3.1</version>
|
||||
<version>2.5.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>xjc</id>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
*********************************************************************** */
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
public class CustomXMLProvider implements IXMLProvider {
|
||||
public class CustomXMLProvider implements IXMLProvider, IProfileProvider {
|
||||
|
||||
protected byte[] zugferdData;
|
||||
|
||||
@@ -48,4 +48,14 @@ public class CustomXMLProvider implements IXMLProvider {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProfile() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProfile(ZUGFeRDConformanceLevel level) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,13 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface IExporterFactory {
|
||||
/**
|
||||
* factory: loads a PDF file and returns an appropriate exporter
|
||||
*
|
||||
* @param pdfFilename binary of a PDF/A1 compliant document
|
||||
* @return the generated exporter
|
||||
* @throws IOException if anything is wrong with filename
|
||||
*/
|
||||
public ZUGFeRDExporter load(String pdfFilename) throws IOException;
|
||||
|
||||
/**
|
||||
@@ -29,6 +36,8 @@ public interface IExporterFactory {
|
||||
* metadata level, this will not e.g. convert graphics to JPG-2000)
|
||||
*
|
||||
* @param pdfBinary binary of a PDF/A1 compliant document
|
||||
* @return the generated exporter
|
||||
* @throws IOException (should not happen at all)
|
||||
*/
|
||||
public ZUGFeRDExporter load(byte[] pdfBinary) throws IOException;
|
||||
|
||||
@@ -37,7 +46,8 @@ public interface IExporterFactory {
|
||||
* metadata level, this will not e.g. convert graphics to JPG-2000)
|
||||
*
|
||||
* @param pdfSource source to read a PDF/A1 compliant document from
|
||||
* @throws IOException
|
||||
* @throws IOException if anything is wrong with inputstream
|
||||
* @return the generated ZUGFeRDExporter
|
||||
*/
|
||||
public ZUGFeRDExporter load(InputStream pdfSource) throws IOException;
|
||||
|
||||
|
||||
@@ -22,4 +22,6 @@ public interface IProfileProvider {
|
||||
|
||||
public String getProfile();
|
||||
|
||||
public void setProfile(ZUGFeRDConformanceLevel level);
|
||||
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
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
|
||||
* @date 2014-05-10
|
||||
* dated 2014-05-10
|
||||
*/
|
||||
|
||||
|
||||
@@ -38,6 +38,24 @@ public interface IZUGFeRDExportableContact {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* customer global identification assigned by the seller
|
||||
*
|
||||
* @return customer identification
|
||||
*/
|
||||
default String getGlobalID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* customer global identification scheme
|
||||
*
|
||||
* @return customer identification
|
||||
*/
|
||||
default String getGlobalIDScheme() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* First and last name of the recipient
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.math.BigDecimal;
|
||||
*
|
||||
* @author jstaerk
|
||||
* @version 1.2.0
|
||||
* @date 2014-05-10
|
||||
* dated 2014-05-10
|
||||
*/
|
||||
|
||||
public interface IZUGFeRDExportableProduct {
|
||||
|
||||
@@ -29,10 +29,19 @@ package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
public interface IZUGFeRDExportableTransaction {
|
||||
|
||||
/**
|
||||
* appears in /rsm:CrossIndustryDocument/rsm:HeaderExchangedDocument/ram:Name
|
||||
* @return Name of document
|
||||
*/
|
||||
default String getDocumentName() {
|
||||
return "RECHNUNG";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
@@ -64,7 +73,7 @@ public interface IZUGFeRDExportableTransaction {
|
||||
|
||||
/**
|
||||
* 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/>
|
||||
* <p>
|
||||
* 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
|
||||
@@ -115,6 +124,8 @@ public interface IZUGFeRDExportableTransaction {
|
||||
|
||||
/**
|
||||
* the creditors payment informations
|
||||
*
|
||||
* @return an array of IZUGFeRDTradeSettlementPayment
|
||||
*/
|
||||
IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment();
|
||||
|
||||
@@ -236,4 +247,23 @@ public interface IZUGFeRDExportableTransaction {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the ID of the BuyerOrderReferencedDocument, which sits in the ApplicableSupplyChainTradeAgreement
|
||||
* @return the ID of the document
|
||||
*/
|
||||
default String getBuyerOrderReferencedDocumentID() { return null; }
|
||||
|
||||
/**
|
||||
* get the issue timestamp of the BuyerOrderReferencedDocument, which sits in the ApplicableSupplyChainTradeAgreement
|
||||
* @return the IssueDateTime in format CCYY-MM-DDTHH:MM:SS
|
||||
*/
|
||||
default String getBuyerOrderReferencedDocumentIssueDateTime() { return null; }
|
||||
|
||||
/**
|
||||
* get the TotalPrepaidAmount located in SpecifiedTradeSettlementMonetarySummation (v1) or
|
||||
* SpecifiedTradeSettlementHeaderMonetarySummation (v2)
|
||||
* @return the total sum (incl. VAT) of prepayments, i.e. the difference between GrandTotalAmount
|
||||
* and DuePayableAmount
|
||||
*/
|
||||
default BigDecimal getTotalPrepaidAmount() { return BigDecimal.ZERO; }
|
||||
}
|
||||
|
||||
@@ -27,20 +27,20 @@ import java.math.BigDecimal;
|
||||
*
|
||||
* @author jstaerk
|
||||
* @version 1.2.0
|
||||
* @date 2015-10-29
|
||||
* dated 2015-10-29
|
||||
*/
|
||||
public class VATAmount {
|
||||
|
||||
public VATAmount(BigDecimal basis, BigDecimal calculated, String documentCode) {
|
||||
public VATAmount(BigDecimal basis, BigDecimal calculated, String categoryCode) {
|
||||
super();
|
||||
this.basis = basis;
|
||||
this.calculated = calculated;
|
||||
this.documentCode = documentCode;
|
||||
this.categoryCode = categoryCode;
|
||||
}
|
||||
|
||||
BigDecimal basis, calculated;
|
||||
|
||||
String documentCode;
|
||||
String categoryCode;
|
||||
|
||||
public BigDecimal getBasis() {
|
||||
return basis;
|
||||
@@ -58,20 +58,39 @@ public class VATAmount {
|
||||
this.calculated = calculated;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated Use {@link #getCategoryCode() instead}
|
||||
* @return String with category code
|
||||
*/
|
||||
@Deprecated
|
||||
public String getDocumentCode() {
|
||||
return documentCode;
|
||||
return categoryCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param documentCode as String
|
||||
* @deprecated Use {@link #setCategoryCode(String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDocumentCode(String documentCode) {
|
||||
this.documentCode = documentCode;
|
||||
this.categoryCode = documentCode;
|
||||
}
|
||||
|
||||
public String getCategoryCode() {
|
||||
return categoryCode;
|
||||
}
|
||||
|
||||
public void setCategoryCode(String categoryCode) {
|
||||
this.categoryCode = categoryCode;
|
||||
}
|
||||
|
||||
public VATAmount add(VATAmount v) {
|
||||
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.documentCode);
|
||||
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode);
|
||||
}
|
||||
|
||||
public VATAmount subtract(VATAmount v) {
|
||||
return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.documentCode);
|
||||
return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.categoryCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +31,13 @@ import org.apache.xmpbox.schema.XMPSchema;
|
||||
|
||||
public class XMPSchemaZugferd extends XMPSchema {
|
||||
|
||||
/**
|
||||
/***
|
||||
* This is what needs to be added to the RDF metadata - basically the name of the embedded Zugferd file
|
||||
* @param metadata the xmp to be added to
|
||||
* @param conformanceLevel e.g. conformanceLevel.EN16931
|
||||
* @param URN the xml URI for the XMP
|
||||
* @param prefix the xml namespace prefix for the XMP, zf for ZUGFeRD, fx for Factur-X
|
||||
* @param filename the filename of the invoice
|
||||
*/
|
||||
public XMPSchemaZugferd(XMPMetadata metadata, ZUGFeRDConformanceLevel conformanceLevel, String URN, String prefix, String filename) {
|
||||
super(metadata, URN, prefix, "ZUGFeRD Schema");
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import org.mustangproject.ZUGFeRD.model.CrossIndustryDocumentType;
|
||||
import org.mustangproject.ZUGFeRD.model.DocumentContextParameterTypeConstants;
|
||||
import org.mustangproject.ZUGFeRD.model.ZFNamespacePrefixMapper;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
@@ -27,13 +28,27 @@ import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
public class ZUGFeRD1PullProvider implements IXMLProvider {
|
||||
public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
|
||||
|
||||
|
||||
protected byte[] zugferdData;
|
||||
private Marshaller marshaller;
|
||||
|
||||
private boolean isTest;
|
||||
private ZUGFeRDConformanceLevel level;
|
||||
|
||||
|
||||
public void setProfile(ZUGFeRDConformanceLevel level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public String getProfile() {
|
||||
switch (level) {
|
||||
case BASIC: return DocumentContextParameterTypeConstants.BASIC;
|
||||
case COMFORT: return DocumentContextParameterTypeConstants.COMFORT;
|
||||
default: return DocumentContextParameterTypeConstants.EXTENDED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -59,7 +74,7 @@ public class ZUGFeRD1PullProvider implements IXMLProvider {
|
||||
private String createZugferdXMLForTransaction(IZUGFeRDExportableTransaction trans) {
|
||||
|
||||
JAXBElement<CrossIndustryDocumentType> jaxElement =
|
||||
new ZUGFeRDTransactionModelConverter(trans).withTest(isTest).convertToModel();
|
||||
new ZUGFeRDTransactionModelConverter(trans).withTest(isTest).withProfile(getProfile()).convertToModel();
|
||||
|
||||
try {
|
||||
return marshalJaxToXMLString(jaxElement);
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -70,6 +71,11 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
|
||||
|
||||
protected byte[] zugferdData;
|
||||
private IZUGFeRDExportableTransaction trans;
|
||||
private ZUGFeRDConformanceLevel level;
|
||||
|
||||
public void setProfile(ZUGFeRDConformanceLevel level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* enables the flag to indicate a test invoice in the XML structure
|
||||
@@ -77,7 +83,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
|
||||
public void setTest() {
|
||||
}
|
||||
|
||||
private String nDigitFormat(BigDecimal value, int scale) {
|
||||
public static String nDigitFormat(BigDecimal value, int scale) {
|
||||
/*
|
||||
* I needed 123,45, locale independent.I tried
|
||||
* NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is locale
|
||||
@@ -92,44 +98,25 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
|
||||
* http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html in the
|
||||
* end I decided to calculate myself and take eur+sparator+cents
|
||||
*
|
||||
* This function will cut off, i.e. floor() subcent values Tests:
|
||||
* System.err.println(utils.currencyFormat(new BigDecimal(0),
|
||||
* ".")+"\n"+utils.currencyFormat(new BigDecimal("-1.10"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.1"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.01"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3489"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3419"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("12"), ","));
|
||||
*
|
||||
* results 0.00 -1,10 -1,10 -1,01 20000123,34 20000123,34 12,00
|
||||
*/
|
||||
value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); // first, round so that e.g.
|
||||
// 1.189999999999999946709294817992486059665679931640625
|
||||
// becomes 1.19
|
||||
char[] repeat = new char[scale];
|
||||
Arrays.fill(repeat, '0');
|
||||
|
||||
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
|
||||
otherSymbols.setDecimalSeparator('.');
|
||||
DecimalFormat dec = new DecimalFormat("0." + new String(repeat), otherSymbols);
|
||||
return dec.format(value);
|
||||
return value.setScale(scale, RoundingMode.HALF_UP).toPlainString();
|
||||
|
||||
}
|
||||
|
||||
private String vatFormat(BigDecimal value) {
|
||||
return nDigitFormat(value, 2);
|
||||
return ZUGFeRD2PullProvider.nDigitFormat(value, 2);
|
||||
}
|
||||
|
||||
private String currencyFormat(BigDecimal value) {
|
||||
return nDigitFormat(value, 2);
|
||||
return ZUGFeRD2PullProvider.nDigitFormat(value, 2);
|
||||
}
|
||||
|
||||
private String priceFormat(BigDecimal value) {
|
||||
return nDigitFormat(value, 4);
|
||||
return ZUGFeRD2PullProvider.nDigitFormat(value, 4);
|
||||
}
|
||||
|
||||
private String quantityFormat(BigDecimal value) {
|
||||
return nDigitFormat(value, 4);
|
||||
return ZUGFeRD2PullProvider.nDigitFormat(value, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -158,6 +145,10 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
|
||||
|
||||
}
|
||||
|
||||
private BigDecimal getTotalPrepaid() {
|
||||
return trans.getTotalPrepaidAmount();
|
||||
}
|
||||
|
||||
private BigDecimal getTotalGross() {
|
||||
|
||||
BigDecimal res = getTotal();
|
||||
@@ -214,9 +205,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
|
||||
SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); //$NON-NLS-1$
|
||||
String senderReg = "";
|
||||
if (trans.getOwnOrganisationFullPlaintextInfo() != null) {
|
||||
senderReg = "" + "<ram:IncludedCINote>\n" + " <ram:Content>\n"
|
||||
senderReg = "" + "<ram:IncludedNote>\n" + " <ram:Content>\n"
|
||||
+ trans.getOwnOrganisationFullPlaintextInfo() + " </ram:Content>\n"
|
||||
+ "<ram:SubjectCode>REG</ram:SubjectCode>\n" + "</ram:IncludedCINote>\n";
|
||||
+ "<ram:SubjectCode>REG</ram:SubjectCode>\n" + "</ram:IncludedNote>\n";
|
||||
|
||||
}
|
||||
|
||||
@@ -378,11 +369,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
|
||||
+ " <ram:LineOne>" + trans.getRecipient().getStreet() + "</ram:LineOne>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <ram:CityName>" + trans.getRecipient().getLocation() + "</ram:CityName>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <ram:CountryID>" + trans.getRecipient().getCountry() + "</ram:CountryID>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </ram:PostalTradeAddress>\n" //$NON-NLS-1$
|
||||
+ " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
|
||||
+ " </ram:PostalTradeAddress>\n"; //$NON-NLS-1$
|
||||
if (trans.getRecipient().getVATID() != null) {
|
||||
xml += " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
|
||||
+ " <ram:ID schemeID=\"VA\">" + trans.getRecipient().getVATID() + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
|
||||
+ " </ram:BuyerTradeParty>\n" //$NON-NLS-1$
|
||||
+ " </ram:SpecifiedTaxRegistration>\n"; //$NON-NLS-1$
|
||||
}
|
||||
xml += " </ram:BuyerTradeParty>\n" //$NON-NLS-1$
|
||||
// + " <BuyerOrderReferencedDocument>\n"
|
||||
// + " <IssueDateTime format=\"102\">20130301</IssueDateTime>\n"
|
||||
// + " <ID>2013-471331</ID>\n"
|
||||
@@ -412,8 +405,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
|
||||
+ " </ram:PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
|
||||
+ " <ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
|
||||
+ " <ram:BICID>" + payment.getOwnBIC() + "</ram:BICID>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <ram:GermanBankleitzahlID>" + payment.getOwnBLZ() //$NON-NLS-1$
|
||||
+ "</ram:GermanBankleitzahlID>\n" //$NON-NLS-1$
|
||||
// + " <ram:Name>"+trans.getOwnBankName()+"</ram:Name>\n" //$NON-NLS-1$
|
||||
// //$NON-NLS-2$
|
||||
+ " </ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
|
||||
@@ -490,8 +481,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
|
||||
+ " <ram:GrandTotalAmount>" + currencyFormat(getTotalGross()) + "</ram:GrandTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
// //
|
||||
// currencyID=\"EUR\"
|
||||
// + " <TotalPrepaidAmount currencyID=\"EUR\">0.00</TotalPrepaidAmount>\n"
|
||||
+ " <ram:DuePayableAmount>" + currencyFormat(getTotalGross()) + "</ram:DuePayableAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <ram:TotalPrepaidAmount currencyID=\"EUR\">" + currencyFormat(getTotalPrepaid()) + "</ram:TotalPrepaidAmount>\n"
|
||||
+ " <ram:DuePayableAmount>" + currencyFormat(getTotalGross().subtract(getTotalPrepaid())) + "</ram:DuePayableAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
// //
|
||||
// currencyID=\"EUR\"
|
||||
+ " </ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n" //$NON-NLS-1$
|
||||
|
||||
@@ -195,15 +195,16 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
|
||||
/**
|
||||
* All files are PDF/A-3, setConformance refers to the level conformance.
|
||||
* <p/>
|
||||
*
|
||||
* PDF/A-3 has three conformance levels, called "A", "U" and "B".
|
||||
* <p/>
|
||||
* <p>
|
||||
* PDF/A-3-B where B means only visually preservable, U -standard for Mustang-
|
||||
* means visually and unicode preservable and A means full compliance, i.e.
|
||||
* visually, unicode and structurally preservable and tagged PDF, i.e. useful
|
||||
* metainformation for blind people.
|
||||
* <p/>
|
||||
* <p>
|
||||
* Feel free to pass "A" as new level if you know what you are doing :-)
|
||||
* @param newLevel "A", "U" or "B"
|
||||
*
|
||||
* @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead
|
||||
*/
|
||||
@@ -217,16 +218,17 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
|
||||
/**
|
||||
* All files are PDF/A-3, setConformance refers to the level conformance.
|
||||
* <p/>
|
||||
* <p>
|
||||
* PDF/A-3 has three conformance levels, called "A", "U" and "B".
|
||||
* <p/>
|
||||
* <p>
|
||||
* PDF/A-3-B where B means only visually preservable, U -standard for Mustang-
|
||||
* means visually and unicode preservable and A means full compliance, i.e.
|
||||
* visually, unicode and structurally preservable and tagged PDF, i.e. useful
|
||||
* metainformation for blind people.
|
||||
* <p/>
|
||||
* <p>
|
||||
* Feel free to pass "A" as new level if you know what you are doing :-)
|
||||
*
|
||||
* @param newLevel "A", "U" or "B"
|
||||
* @deprecated Use
|
||||
* {@link #setConformanceLevel(org.mustangproject.ZUGFeRD.PDFAConformanceLevel)}
|
||||
* instead
|
||||
@@ -251,7 +253,10 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
ignoreA1Errors = true;
|
||||
}
|
||||
|
||||
/**
|
||||
/***
|
||||
* load from a pdf which is already A/3
|
||||
* @param filename the PDF
|
||||
* @throws IOException if anything is wrong with filename
|
||||
* @deprecated Use the factory method {@link #createFromPDFA3(String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@@ -259,19 +264,34 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
doc = PDDocument.load(new File(filename));
|
||||
}
|
||||
|
||||
/***
|
||||
* factory create a ZUGFeRD exporter for a PDF/A-3 pdf file
|
||||
* @param filename of the pdf
|
||||
* @return the created ZUGFeRDExporter
|
||||
* @throws IOException if something is wrong with filename
|
||||
*/
|
||||
public static ZUGFeRDExporter createFromPDFA3(String filename) throws IOException {
|
||||
return new ZUGFeRDExporter(PDDocument.load(new File(filename)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use the factory method {@link #createFromPDFA3(InputStream)}
|
||||
* instead
|
||||
* load from a pdf which is already A/3 from filestream
|
||||
* @param file InputStream to load pdf from
|
||||
* @deprecated Use the factory method {@link #createFromPDFA3(InputStream)} instead
|
||||
* @throws IOException in case anything is wrong with file
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public void loadPDFA3(InputStream file) throws IOException {
|
||||
doc = PDDocument.load(file);
|
||||
}
|
||||
|
||||
/***
|
||||
* factory create a ZUGFeRD exporter for a PDF/A-3 inputstream
|
||||
* @param pdfSource the InputStream of the pdf
|
||||
* @return the created ZUGFeRDExporter
|
||||
* @throws IOException (should not happen)
|
||||
*/
|
||||
public static ZUGFeRDExporter createFromPDFA3(InputStream pdfSource) throws IOException {
|
||||
return new ZUGFeRDExporter(PDDocument.load(pdfSource));
|
||||
}
|
||||
@@ -279,7 +299,13 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
/**
|
||||
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
|
||||
* metadata level, this will not e.g. convert graphics to JPG-2000)
|
||||
*
|
||||
* @param filename the pdf
|
||||
* @param producer the name of the xmp producer (app)
|
||||
* @param creator the name of the xmp creator (user)
|
||||
* @param attachZugferdHeaders whether to attach XMP ZUGFeRD headers
|
||||
* @return the created PDFbox PDDocumentCatalog
|
||||
* @throws IOException if anything is wrong with file
|
||||
* @throws TransformerException in case of xml (XMP) parsing issues
|
||||
* @deprecated use the {@link ZUGFeRDExporterFromA1Factory} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@@ -291,7 +317,18 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
return doc.getDocumentCatalog();
|
||||
}
|
||||
|
||||
/**
|
||||
/***
|
||||
*
|
||||
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
|
||||
* metadata level, this will not e.g. convert graphics to JPG-2000)
|
||||
|
||||
* @param file the InputStream of the pdf
|
||||
* @param producer the name of the xmp producer (app)
|
||||
* @param creator the name of the xmp creator (user)
|
||||
* @param attachZugferdHeaders whether to attach XMP ZUGFeRD headers
|
||||
* @return the created PDFbox PDDocumentCatalog
|
||||
* @throws IOException if anything is wrong with file
|
||||
* @throws TransformerException in case of xml (XMP) parsing issues
|
||||
* @deprecated use the {@link ZUGFeRDExporterFromA1Factory} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@@ -303,6 +340,7 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
return doc.getDocumentCatalog();
|
||||
}
|
||||
|
||||
|
||||
private IExporterFactory createPDFA1Factory() {
|
||||
ZUGFeRDExporterFromA1Factory factory = new ZUGFeRDExporterFromA1Factory();
|
||||
if (ignoreA1Errors) {
|
||||
@@ -325,10 +363,11 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
* populate the XML. This parameter may be null, if so the XML data
|
||||
* should hav ebeen set via
|
||||
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
|
||||
* @throws IOException if anything is wrong with already loaded PDF
|
||||
*/
|
||||
public void PDFattachZugferdFile(IZUGFeRDExportableTransaction trans) throws IOException {
|
||||
prepareDocument();
|
||||
|
||||
((IProfileProvider) xmlProvider).setProfile(profile);
|
||||
xmlProvider.generateXML(trans);
|
||||
String filename = getFilenameForVersion(ZFVersion);
|
||||
PDFAttachGenericFile(doc, filename, "Alternative",
|
||||
@@ -339,6 +378,11 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* Perform the final export to a now ZUGFeRD-enriched PDF file
|
||||
* @param ZUGFeRDfilename the pdf file name
|
||||
* @throws IOException if anything is wrong in the target location
|
||||
*/
|
||||
public void export(String ZUGFeRDfilename) throws IOException {
|
||||
if (!documentPrepared) {
|
||||
prepareDocument();
|
||||
@@ -353,6 +397,12 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* Perform the final export to a now ZUGFeRD-enriched PDF file as OutputStream
|
||||
* @param output the OutputStream
|
||||
* @throws IOException if anything is wrong in the OutputStream
|
||||
*/
|
||||
public void export(OutputStream output) throws IOException {
|
||||
if (!documentPrepared) {
|
||||
prepareDocument();
|
||||
@@ -376,7 +426,7 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
* @param description Human-readable description of the file content
|
||||
* @param subType type of the data e.g. could be "text/xml" - mime like
|
||||
* @param data the binary data of the file/attachment
|
||||
* @throws java.io.IOException
|
||||
* @throws java.io.IOException if anything is wrong with filename
|
||||
*/
|
||||
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
|
||||
String subType, byte[] data) throws IOException {
|
||||
@@ -446,6 +496,7 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
* API or component.
|
||||
*
|
||||
* @param zugferdData XML data to be set as a byte array (XML file in raw form).
|
||||
* @throws IOException (should not happen)
|
||||
*/
|
||||
public void setZUGFeRDXMLData(byte[] zugferdData) throws IOException {
|
||||
CustomXMLProvider cus = new CustomXMLProvider();
|
||||
@@ -495,7 +546,7 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
* neccessary PDF/A schema extension description to be able to add this
|
||||
* information to RDF
|
||||
*
|
||||
* @param metadata
|
||||
* @param metadata the PDFbox XMPMetadata object
|
||||
*/
|
||||
protected void addXMP(XMPMetadata metadata) {
|
||||
|
||||
@@ -607,7 +658,7 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
/**
|
||||
* the human author (use factory method instead)
|
||||
*
|
||||
* @param creator
|
||||
* @param creator the (human) name who created the PDF
|
||||
*/
|
||||
@Deprecated
|
||||
public void setCreator(String creator) {
|
||||
@@ -617,7 +668,7 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
/**
|
||||
* the CreatorTool attribute for the PDF
|
||||
*
|
||||
* @param creator
|
||||
* @param creatorTool the application which created the PDF
|
||||
*/
|
||||
protected void setCreatorTool(String creatorTool) {
|
||||
this.creatorTool = creatorTool;
|
||||
@@ -626,7 +677,7 @@ public class ZUGFeRDExporter implements Closeable {
|
||||
/**
|
||||
* the authoring software (use factory method instead)
|
||||
*
|
||||
* @param producer
|
||||
* @param producer the authoring software
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProducer(String producer) {
|
||||
|
||||
@@ -173,14 +173,14 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
||||
|
||||
/**
|
||||
* All files are PDF/A-3, setConformance refers to the level conformance.
|
||||
* <p/>
|
||||
* <p>
|
||||
* PDF/A-3 has three coformance levels, called "A", "U" and "B".
|
||||
* <p/>
|
||||
* <p>
|
||||
* PDF/A-3-B where B means only visually preservable, U -standard for Mustang-
|
||||
* means visually and unicode preservable and A means full compliance, i.e.
|
||||
* visually, unicode and structurally preservable and tagged PDF, i.e. useful
|
||||
* metainformation for blind people.
|
||||
* <p/>
|
||||
* <p>
|
||||
* Feel free to pass "A" as new level if you know what you are doing :-)
|
||||
*/
|
||||
public IExporterFactory setConformanceLevel(PDFAConformanceLevel newLevel) {
|
||||
|
||||
@@ -46,6 +46,9 @@ import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -65,12 +68,12 @@ public class ZUGFeRDImporter {
|
||||
*/
|
||||
private byte[] rawXML = null;
|
||||
private String xmpString = null; // XMP metadata
|
||||
private Document document;
|
||||
|
||||
public ZUGFeRDImporter(String pdfFilename) {
|
||||
try {
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pdfFilename));
|
||||
|
||||
try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) {
|
||||
extractLowLevel(bis);
|
||||
bis.close();
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
|
||||
throw new ZUGFeRDExportException(e);
|
||||
@@ -125,7 +128,10 @@ public class ZUGFeRDImporter {
|
||||
|
||||
|
||||
private void extractFiles(Map<String, PDComplexFileSpecification> names) throws IOException {
|
||||
for (String filename : names.keySet()) {
|
||||
for (String alias : names.keySet()) {
|
||||
|
||||
PDComplexFileSpecification fileSpec = names.get(alias);
|
||||
String filename=fileSpec.getFilename();
|
||||
/**
|
||||
* currently (in the release candidate of version 1) only one attached file with
|
||||
* the name ZUGFeRD-invoice.xml is allowed
|
||||
@@ -133,7 +139,6 @@ public class ZUGFeRDImporter {
|
||||
if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml"))) { //$NON-NLS-1$
|
||||
containsMeta = true;
|
||||
|
||||
PDComplexFileSpecification fileSpec = names.get(filename);
|
||||
PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
|
||||
// String embeddedFilename = filePath + filename;
|
||||
// File file = new File(filePath + filename);
|
||||
@@ -142,15 +147,13 @@ public class ZUGFeRDImporter {
|
||||
// ByteArrayOutputStream();
|
||||
// FileOutputStream fos = new FileOutputStream(file);
|
||||
|
||||
rawXML = embeddedFile.toByteArray();
|
||||
setMeta(new String(rawXML));
|
||||
setRawXML(embeddedFile.toByteArray());
|
||||
|
||||
// fos.write(embeddedFile.getByteArray());
|
||||
// fos.close();
|
||||
}
|
||||
if (filename.startsWith("additional_data")) {
|
||||
|
||||
PDComplexFileSpecification fileSpec = names.get(filename);
|
||||
PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
|
||||
additionalXMLs.put(filename, embeddedFile.toByteArray());
|
||||
|
||||
@@ -173,13 +176,52 @@ public class ZUGFeRDImporter {
|
||||
System.err.println(output);
|
||||
}
|
||||
|
||||
private Document getDocument() throws ParserConfigurationException, IOException, SAXException, TransformerException {
|
||||
private Document getDocument() { return document; }
|
||||
|
||||
public void setRawXML(byte[] rawXML) throws IOException {
|
||||
this.rawXML = rawXML;
|
||||
try {
|
||||
setDocument();
|
||||
} catch (ParserConfigurationException | SAXException e) {
|
||||
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
|
||||
throw new ZUGFeRDExportException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setDocument() throws ParserConfigurationException, IOException, SAXException {
|
||||
DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
|
||||
xmlFact.setNamespaceAware(false);
|
||||
DocumentBuilder builder = xmlFact.newDocumentBuilder();
|
||||
Document doc = builder.parse(new ByteArrayInputStream(rawXML));
|
||||
//prettyPrint(doc);
|
||||
return doc;
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(rawXML);
|
||||
is.skip(guessBOMSize(is));
|
||||
document = builder.parse(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips over a BOM at the beginning of the given ByteArrayInputStream, if one exists.
|
||||
* @param is the ByteArrayInputStream used
|
||||
* @throws IOException
|
||||
* @see <a href="https://www.w3.org/TR/xml/#sec-guessing">Autodetection of Character Encodings</a>
|
||||
*/
|
||||
private int guessBOMSize(ByteArrayInputStream is) throws IOException {
|
||||
byte[] pad = new byte[4];
|
||||
is.read(pad);
|
||||
is.reset();
|
||||
int test2 = ((pad[0] & 0xFF) << 8) | (pad[1] & 0xFF);
|
||||
int test3 = ((test2 & 0xFFFF) << 8) | (pad[2] & 0xFF);
|
||||
int test4 = ((test3 & 0xFFFFFF) << 8) | (pad[3] & 0xFF);
|
||||
//
|
||||
if (test4 == 0x0000FEFF || test4 == 0xFFFE0000 || test4 == 0x0000FFFE || test4 == 0xFEFF0000) {
|
||||
// UCS-4: BOM takes 4 bytes
|
||||
return 4;
|
||||
} else if (test3 == 0xEFBBFF) {
|
||||
// UTF-8: BOM takes 3 bytes
|
||||
return 3;
|
||||
} else if (test2 == 0xFEFF || test2 == 0xFFFE) {
|
||||
// UTF-16: BOM takes 2 bytes
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private String extractString(String xpathStr) {
|
||||
@@ -192,10 +234,7 @@ public class ZUGFeRDImporter {
|
||||
XPathFactory xpathFact = XPathFactory.newInstance();
|
||||
XPath xpath = xpathFact.newXPath();
|
||||
result = xpath.evaluate(xpathStr, document);
|
||||
} catch (ParserConfigurationException e) {
|
||||
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
|
||||
throw new ZUGFeRDExportException(e);
|
||||
} catch (IOException | SAXException | TransformerException | XPathExpressionException e) {
|
||||
} catch (XPathExpressionException e) {
|
||||
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
|
||||
throw new ZUGFeRDExportException(e);
|
||||
}
|
||||
@@ -300,8 +339,8 @@ public class ZUGFeRDImporter {
|
||||
/**
|
||||
* @param meta raw XML to be set
|
||||
*/
|
||||
public void setMeta(String meta) {
|
||||
this.rawXML = meta.getBytes();
|
||||
public void setMeta(String meta) throws IOException {
|
||||
setRawXML(meta.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,6 +385,7 @@ public class ZUGFeRDImporter {
|
||||
|
||||
/**
|
||||
* Returns the raw XML data as extracted from the ZUGFeRD PDF file.
|
||||
* @return the raw ZUGFeRD XML data
|
||||
*/
|
||||
public byte[] getRawXML() {
|
||||
return rawXML;
|
||||
@@ -369,7 +409,7 @@ public class ZUGFeRDImporter {
|
||||
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");
|
||||
Scanner s = new Scanner(is, "UTF-8").useDelimiter("\\A");
|
||||
return s.hasNext() ? s.next() : "";
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -30,51 +31,7 @@ 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.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.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;
|
||||
import org.mustangproject.ZUGFeRD.model.*;
|
||||
|
||||
class ZUGFeRDTransactionModelConverter {
|
||||
private static final SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd");
|
||||
@@ -84,6 +41,7 @@ class ZUGFeRDTransactionModelConverter {
|
||||
private final Totals totals;
|
||||
private boolean isTest;
|
||||
private String currency = "EUR";
|
||||
private String profile;
|
||||
|
||||
|
||||
ZUGFeRDTransactionModelConverter(IZUGFeRDExportableTransaction trans) {
|
||||
@@ -113,7 +71,7 @@ class ZUGFeRDTransactionModelConverter {
|
||||
DocumentContextParameterType contextParameter = xmlFactory
|
||||
.createDocumentContextParameterType();
|
||||
IDType idType = xmlFactory.createIDType();
|
||||
idType.setValue(DocumentContextParameterTypeConstants.EXTENDED);
|
||||
idType.setValue(profile);
|
||||
contextParameter.setID(idType);
|
||||
context.getGuidelineSpecifiedDocumentContextParameter().add(
|
||||
contextParameter);
|
||||
@@ -149,7 +107,7 @@ class ZUGFeRDTransactionModelConverter {
|
||||
document.setTypeCode(documentCodeType);
|
||||
|
||||
TextType name = xmlFactory.createTextType();
|
||||
name.setValue("RECHNUNG");
|
||||
name.setValue(trans.getDocumentName());
|
||||
document.getName().add(name);
|
||||
|
||||
if (trans.getOwnOrganisationFullPlaintextInfo() != null) {
|
||||
@@ -167,7 +125,7 @@ class ZUGFeRDTransactionModelConverter {
|
||||
if (trans.getReferenceNumber() != null && !"".equals(trans.getReferenceNumber())) {
|
||||
NoteType referenceInfo = xmlFactory.createNoteType();
|
||||
TextType referenceInfoContent = xmlFactory.createTextType();
|
||||
referenceInfoContent.setValue("Ursprungsbeleg: " + trans.getReferenceNumber());
|
||||
referenceInfoContent.setValue(trans.getReferenceNumber());
|
||||
referenceInfo.getContent().add(referenceInfoContent);
|
||||
document.getIncludedNote().add(referenceInfo);
|
||||
}
|
||||
@@ -199,6 +157,15 @@ class ZUGFeRDTransactionModelConverter {
|
||||
tradeAgreement.setBuyerTradeParty(getBuyer());
|
||||
tradeAgreement.setSellerTradeParty(getSeller());
|
||||
|
||||
if (trans.getBuyerOrderReferencedDocumentID() != null) {
|
||||
ReferencedDocumentType refdoc = xmlFactory.createReferencedDocumentType();
|
||||
IDType id = xmlFactory.createIDType();
|
||||
id.setValue(trans.getBuyerOrderReferencedDocumentID());
|
||||
refdoc.getID().add(id);
|
||||
refdoc.setIssueDateTime(trans.getBuyerOrderReferencedDocumentIssueDateTime());
|
||||
tradeAgreement.getBuyerOrderReferencedDocument().add(refdoc);
|
||||
}
|
||||
|
||||
return tradeAgreement;
|
||||
}
|
||||
|
||||
@@ -212,6 +179,12 @@ class ZUGFeRDTransactionModelConverter {
|
||||
buyerID.setValue(trans.getRecipient().getID());
|
||||
buyerTradeParty.getID().add(buyerID);
|
||||
}
|
||||
if (trans.getRecipient().getGlobalID() != null) {
|
||||
IDType globalID = xmlFactory.createIDType();
|
||||
globalID.setValue(trans.getRecipient().getGlobalID());
|
||||
globalID.setSchemeID(trans.getRecipient().getGlobalIDScheme());
|
||||
buyerTradeParty.getGlobalID().add(globalID);
|
||||
}
|
||||
|
||||
TextType buyerName = xmlFactory.createTextType();
|
||||
buyerName.setValue(trans.getRecipient().getName());
|
||||
@@ -422,7 +395,7 @@ class ZUGFeRDTransactionModelConverter {
|
||||
|
||||
TaxCategoryCodeType taxCategoryCode = xmlFactory.createTaxCategoryCodeType();
|
||||
VATAmount vatAmount = VATPercentAmountMap.get(currentTaxPercent);
|
||||
taxCategoryCode.setValue(vatAmount.getDocumentCode());
|
||||
taxCategoryCode.setValue(vatAmount.getCategoryCode());
|
||||
tradeTax.setCategoryCode(taxCategoryCode);
|
||||
|
||||
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
|
||||
@@ -686,9 +659,14 @@ class ZUGFeRDTransactionModelConverter {
|
||||
grandTotalAmount.setValue(currencyFormat(totals.getTotalGross()));
|
||||
monetarySummation.getGrandTotalAmount().add(grandTotalAmount);
|
||||
|
||||
AmountType totalPrepaidAmount = xmlFactory.createAmountType();
|
||||
totalPrepaidAmount.setCurrencyID(currency);
|
||||
totalPrepaidAmount.setValue(currencyFormat(trans.getTotalPrepaidAmount()));
|
||||
monetarySummation.getTotalPrepaidAmount().add(totalPrepaidAmount);
|
||||
|
||||
AmountType duePayableAmount = xmlFactory.createAmountType();
|
||||
duePayableAmount.setCurrencyID(currency);
|
||||
duePayableAmount.setValue(currencyFormat(totals.getTotalGross()));
|
||||
duePayableAmount.setValue(currencyFormat(totals.getTotalGross().subtract(trans.getTotalPrepaidAmount())));
|
||||
monetarySummation.getDuePayableAmount().add(duePayableAmount);
|
||||
|
||||
return monetarySummation;
|
||||
@@ -843,69 +821,25 @@ class ZUGFeRDTransactionModelConverter {
|
||||
|
||||
|
||||
private BigDecimal vatFormat(BigDecimal value) {
|
||||
return nDigitFormat(value, 2);
|
||||
}
|
||||
return value.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
|
||||
private BigDecimal currencyFormat(BigDecimal value) {
|
||||
return nDigitFormat(value, 2);
|
||||
}
|
||||
return value.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
|
||||
private BigDecimal priceFormat(BigDecimal value) {
|
||||
return nDigitFormat(value, 4);
|
||||
}
|
||||
return value.setScale(4, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
|
||||
private BigDecimal quantityFormat(BigDecimal value) {
|
||||
return nDigitFormat(value, 4);
|
||||
}
|
||||
return value.setScale(4, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
|
||||
private BigDecimal nDigitFormat(BigDecimal value, int scale) {
|
||||
/*
|
||||
* I needed 123,45, locale independent.I tried
|
||||
* NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is
|
||||
* locale specific.I also tried DecimalFormat df = new DecimalFormat(
|
||||
* "0,00" ); df.setDecimalSeparatorAlwaysShown(true);
|
||||
* df.setGroupingUsed(false); DecimalFormatSymbols symbols = new
|
||||
* DecimalFormatSymbols(); symbols.setDecimalSeparator(',');
|
||||
* symbols.setGroupingSeparator(' ');
|
||||
* df.setDecimalFormatSymbols(symbols);
|
||||
*
|
||||
* but that would not switch off grouping. Although I liked very much
|
||||
* the (incomplete) "BNF diagram" in
|
||||
* http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html
|
||||
* in the end I decided to calculate myself and take eur+sparator+cents
|
||||
*
|
||||
* This function will cut off, i.e. floor() subcent values Tests:
|
||||
* System.err.println(utils.currencyFormat(new BigDecimal(0),
|
||||
* ".")+"\n"+utils.currencyFormat(new BigDecimal("-1.10"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.1"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.01"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3489"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3419"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("12"), ","));
|
||||
*
|
||||
* results 0.00 -1,10 -1,10 -1,01 20000123,34 20000123,34 12,00
|
||||
*/
|
||||
value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); // first, round
|
||||
// so that
|
||||
// e.g.
|
||||
// 1.189999999999999946709294817992486059665679931640625
|
||||
// becomes
|
||||
// 1.19
|
||||
char[] repeat = new char[scale];
|
||||
Arrays.fill(repeat, '0');
|
||||
|
||||
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
|
||||
otherSymbols.setDecimalSeparator('.');
|
||||
DecimalFormat dec = new DecimalFormat("0." + new String(repeat),
|
||||
otherSymbols);
|
||||
return new BigDecimal(dec.format(value));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -924,7 +858,7 @@ class ZUGFeRDTransactionModelConverter {
|
||||
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
|
||||
BigDecimal percent = currentItem.getProduct().getVATPercent();
|
||||
LineCalc lc = new LineCalc(currentItem);
|
||||
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), trans.getDocumentCode());
|
||||
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), lc.getCategoryCode());
|
||||
VATAmount current = hm.get(percent);
|
||||
if (current == null) {
|
||||
hm.put(percent, itemVATAmount);
|
||||
@@ -958,7 +892,7 @@ class ZUGFeRDTransactionModelConverter {
|
||||
VATAmount itemVATAmount = new VATAmount(
|
||||
logisticsServiceCharge.getTotalAmount(),
|
||||
logisticsServiceCharge.getTotalAmount()
|
||||
.multiply(percent).divide(new BigDecimal(100)), trans.getDocumentCode());
|
||||
.multiply(percent).divide(new BigDecimal(100)), logisticsServiceCharge.getCategoryCode());
|
||||
VATAmount current = hm.get(percent);
|
||||
if (current == null) {
|
||||
hm.put(percent, itemVATAmount);
|
||||
@@ -973,7 +907,7 @@ class ZUGFeRDTransactionModelConverter {
|
||||
BigDecimal percent = charge.getTaxPercent();
|
||||
VATAmount itemVATAmount = new VATAmount(
|
||||
charge.getTotalAmount(), charge.getTotalAmount()
|
||||
.multiply(percent).divide(new BigDecimal(100)), trans.getDocumentCode());
|
||||
.multiply(percent).divide(new BigDecimal(100)), charge.getCategoryCode());
|
||||
VATAmount current = hm.get(percent);
|
||||
if (current == null) {
|
||||
hm.put(percent, itemVATAmount);
|
||||
@@ -992,12 +926,18 @@ class ZUGFeRDTransactionModelConverter {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ZUGFeRDTransactionModelConverter withProfile(String profile) {
|
||||
this.profile = profile;
|
||||
return this;
|
||||
}
|
||||
|
||||
private class LineCalc {
|
||||
|
||||
private BigDecimal totalGross;
|
||||
private BigDecimal itemTotalNetAmount;
|
||||
private BigDecimal itemTotalVATAmount;
|
||||
private BigDecimal itemNetAmount;
|
||||
private String categoryCode;
|
||||
|
||||
|
||||
public LineCalc(IZUGFeRDExportableItem currentItem) {
|
||||
@@ -1040,6 +980,7 @@ class ZUGFeRDTransactionModelConverter {
|
||||
.add(totalCharge)
|
||||
.divide(currentItem.getQuantity(), 4,
|
||||
BigDecimal.ROUND_HALF_UP);
|
||||
categoryCode = currentItem.getCategoryCode();
|
||||
}
|
||||
|
||||
|
||||
@@ -1057,6 +998,8 @@ class ZUGFeRDTransactionModelConverter {
|
||||
return itemNetAmount;
|
||||
}
|
||||
|
||||
public String getCategoryCode() { return categoryCode; }
|
||||
|
||||
}
|
||||
|
||||
private class Totals {
|
||||
|
||||
165
src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java
Normal file
165
src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java
Normal file
@@ -0,0 +1,165 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 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 javax.xml.transform.*;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ZUGFeRDVisualizer {
|
||||
|
||||
static final ClassLoader CLASS_LOADER = ZUGFeRDVisualizer.class.getClassLoader();
|
||||
private static final String RESOURCE_PATH = ""; //$NON-NLS-1$
|
||||
private static final Logger LOG = Logger.getLogger(ZUGFeRDVisualizer.class.getName());
|
||||
// private static File createTempFileResult(final Transformer transformer, final
|
||||
// StreamSource toTransform,
|
||||
// final String suffix) throws TransformerException, IOException {
|
||||
// File result = File.createTempFile("ZUV_", suffix); //$NON-NLS-1$
|
||||
// result.deleteOnExit();
|
||||
//
|
||||
// try (FileOutputStream fos = new FileOutputStream(result)) {
|
||||
// transformer.transform(toTransform, new StreamResult(fos));
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
private TransformerFactory mFactory = null;
|
||||
private Templates mXsltXRTemplate = null;
|
||||
private Templates mXsltHTMLTemplate = null;
|
||||
private Templates mXsltZF1HTMLTemplate = null;
|
||||
|
||||
public ZUGFeRDVisualizer() {
|
||||
mFactory = new net.sf.saxon.TransformerFactoryImpl();
|
||||
// fact = TransformerFactory.newInstance();
|
||||
mFactory.setURIResolver(new ClasspathResourceURIResolver());
|
||||
try {
|
||||
mXsltXRTemplate = mFactory.newTemplates(
|
||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
|
||||
mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource(
|
||||
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html.xsl")));
|
||||
mXsltZF1HTMLTemplate = mFactory.newTemplates(new StreamSource(
|
||||
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt")));
|
||||
} catch (TransformerConfigurationException ex) {
|
||||
LOG.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String visualize(String xmlFilename)
|
||||
throws FileNotFoundException, TransformerException, UnsupportedEncodingException {
|
||||
/**
|
||||
* *
|
||||
* http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf
|
||||
* http://www.ferd-net.de/upload/Dokumente/FACTUR-X_ZUGFeRD_2p0_Teil1_Profil_EN16931_1p03.pdf
|
||||
* http://countwordsfree.com/xmlviewer
|
||||
*/
|
||||
FileInputStream fis=new FileInputStream(xmlFilename);
|
||||
String fileContent="";
|
||||
try {
|
||||
fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename)));
|
||||
} catch (IOException e2) {
|
||||
LOG.log(Level.SEVERE, null, e2);
|
||||
}
|
||||
|
||||
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
String zf1Signature = "rsm:CrossIndustryDocument";
|
||||
if (fileContent.contains(zf1Signature)) {
|
||||
applyZF1SchematronXsl(fis, baos);
|
||||
|
||||
} else {
|
||||
//zf2 or fx
|
||||
applySchematronXsl(fis, iaos);
|
||||
// take the copy of the stream and re-write it to an InputStream
|
||||
PipedInputStream in = new PipedInputStream();
|
||||
PipedOutputStream out;
|
||||
try {
|
||||
out = new PipedOutputStream(in);
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
// write the original OutputStream to the PipedOutputStream
|
||||
// note that in order for the below method to work, you need
|
||||
// to ensure that the data has finished writing to the
|
||||
// ByteArrayOutputStream
|
||||
iaos.writeTo(out);
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.SEVERE, null, e);
|
||||
} finally {
|
||||
// close the PipedOutputStream here because we're done writing data
|
||||
// once this thread has completed its run
|
||||
if (out != null) {
|
||||
// close the PipedOutputStream cleanly
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
LOG.log(Level.SEVERE, null, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
applySchematronXsl2(in, baos);
|
||||
} catch (IOException e1) {
|
||||
LOG.log(Level.SEVERE, null, e1);
|
||||
}
|
||||
}
|
||||
|
||||
return baos.toString("UTF-8");
|
||||
}
|
||||
|
||||
public void applySchematronXsl(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||
throws TransformerException {
|
||||
Transformer transformer = mXsltXRTemplate.newTransformer();
|
||||
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||
}
|
||||
|
||||
public void applyZF1SchematronXsl(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||
throws TransformerException {
|
||||
Transformer transformer = mXsltZF1HTMLTemplate.newTransformer();
|
||||
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||
}
|
||||
|
||||
public void applySchematronXsl2(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||
throws TransformerException {
|
||||
Transformer transformer = mXsltHTMLTemplate.newTransformer();
|
||||
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||
}
|
||||
|
||||
private static class ClasspathResourceURIResolver implements URIResolver {
|
||||
ClasspathResourceURIResolver() {
|
||||
// Do nothing, just prevents synthetic access warning.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Source resolve(String href, String base) throws TransformerException {
|
||||
return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + href));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
package org.mustangproject.ZUGFeRD.model;
|
||||
|
||||
public class DocumentContextParameterTypeConstants {
|
||||
public static final String BASIC = "urn:ferd:CrossIndustryDocument:invoice:1p0:basic";
|
||||
public static final String COMFORT = "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort";
|
||||
public static final String EXTENDED = "urn:ferd:CrossIndustryDocument:invoice:1p0:extended";
|
||||
// this does not look complete :-/
|
||||
}
|
||||
|
||||
@@ -30,8 +30,14 @@ import org.mustangproject.ZUGFeRD.*;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@@ -104,8 +110,7 @@ public class Toecount {
|
||||
+ "\t\t[--source-xml <filename>]: set input XML file\r\n"
|
||||
+ "\t\t[--out <filename>]: set output PDF file\r\n"
|
||||
+ "\t\t[--format <fx|zf>]: enable factur-x or ZUGFeRD\r\n"
|
||||
+ "\t\t[--version <1|2>]: set ZUGFeRD version\r\n"
|
||||
+ "\t\t[--profile <...>]: set ZUGFeRD profile\r\n"
|
||||
+ "\t\t[--version <1|2>]: set ZUGFeRD version\r\n" + "\t\t[--profile <...>]: set ZUGFeRD profile\r\n"
|
||||
+ "\t\t\tFor ZUGFeRD v1: <B>ASIC, <C>OMFORT or <E>XTENDED\r\n"
|
||||
+ "\t\t\tFor ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, E<X>TENDED\r\n");
|
||||
}
|
||||
@@ -114,11 +119,15 @@ public class Toecount {
|
||||
* Asks the user (repeatedly, if neccessary) on the command line for a String
|
||||
* (offering a defaultValue) conforming to a Regex pattern
|
||||
*
|
||||
* @param prompt the question to be asked to the user
|
||||
* @param defaultValue the default return value if user hits enter
|
||||
* @param pattern a regex of acceptable values
|
||||
* @param prompt
|
||||
* the question to be asked to the user
|
||||
* @param defaultValue
|
||||
* the default return value if user hits enter
|
||||
* @param pattern
|
||||
* a regex of acceptable values
|
||||
* @return the user answer conforming to pattern
|
||||
* @throws Exception if pattern not compielable or IOexception on input
|
||||
* @throws Exception
|
||||
* if pattern not compielable or IOexception on input
|
||||
*/
|
||||
protected static String getStringFromUser(String prompt, String defaultValue, String pattern) throws Exception {
|
||||
String input = "";
|
||||
@@ -157,15 +166,15 @@ public class Toecount {
|
||||
/**
|
||||
* Prompts the user for a input or output filename
|
||||
*
|
||||
* @param the text the user is asked
|
||||
* @param a default Filename
|
||||
* @param expectedExtension will warn if filename does not match expected file extension
|
||||
* @param ensureFileExists will warn if file does NOT exist (for input files)
|
||||
* @param prompt the text the user is asked
|
||||
* @param defaultFilename a default Filename
|
||||
* @param expectedExtension will warn if filename does not match expected file extension
|
||||
* @param ensureFileExists will warn if file does NOT exist (for input files)
|
||||
* @param ensureFileNotExists will warn if file DOES exist (for output files)
|
||||
* @return String
|
||||
*/
|
||||
protected static String getFilenameFromUser(String prompt, String defaultFilename, String expectedExtension,
|
||||
boolean ensureFileExists, boolean ensureFileNotExists) {
|
||||
boolean ensureFileExists, boolean ensureFileNotExists) {
|
||||
boolean fileExistenceOK = false;
|
||||
String selectedName = "";
|
||||
do {
|
||||
@@ -235,6 +244,8 @@ public class Toecount {
|
||||
|
||||
// Option: Help
|
||||
Option<Boolean> helpOption = parser.addBooleanOption('h', "help");
|
||||
// Option: Action
|
||||
Option<String> actionOption = parser.addStringOption('a', "action");
|
||||
|
||||
// Generic options available for multiple command
|
||||
// --source: input file
|
||||
@@ -292,14 +303,15 @@ public class Toecount {
|
||||
}
|
||||
|
||||
// Retrieve all options
|
||||
String action = parser.getOptionValue(actionOption);
|
||||
String directoryName = parser.getOptionValue(dirnameOption);
|
||||
Boolean filesFromStdIn = parser.getOptionValue(filesFromStdInOption, Boolean.FALSE);
|
||||
Boolean combineRequested = parser.getOptionValue(combineOption, Boolean.FALSE);
|
||||
Boolean extractRequested = parser.getOptionValue(extractOption, Boolean.FALSE);
|
||||
Boolean helpRequested = parser.getOptionValue(helpOption, Boolean.FALSE);
|
||||
Boolean upgradeRequested = parser.getOptionValue(upgradeOption, Boolean.FALSE);
|
||||
Boolean combineRequested = parser.getOptionValue(combineOption, Boolean.FALSE) || ((action!=null)&&(action.equals("combine")));
|
||||
Boolean extractRequested = parser.getOptionValue(extractOption, Boolean.FALSE) || ((action!=null)&&(action.equals("extract")));
|
||||
Boolean helpRequested = parser.getOptionValue(helpOption, Boolean.FALSE) || ((action!=null)&&(action.equals("help")));
|
||||
Boolean upgradeRequested = parser.getOptionValue(upgradeOption, Boolean.FALSE) || ((action!=null)&&(action.equals("upgrade")));
|
||||
Boolean ignoreFileExt = parser.getOptionValue(ignoreFileExtOption, Boolean.FALSE);
|
||||
Boolean a3only = parser.getOptionValue(a3onlyOption, Boolean.FALSE);
|
||||
Boolean a3only = parser.getOptionValue(a3onlyOption, Boolean.FALSE) || ((action!=null)&&(action.equals("a3")));
|
||||
String sourceName = parser.getOptionValue(sourceOption);
|
||||
String sourceXMLName = parser.getOptionValue(sourceXmlOption);
|
||||
String outName = parser.getOptionValue(outOption);
|
||||
@@ -341,7 +353,7 @@ public class Toecount {
|
||||
System.out.println("ZUGFeRD 1.0 XML source set to " + xmlName);
|
||||
}
|
||||
if (outName == null) {
|
||||
outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "factur-x.xml", "xml", false, true);
|
||||
outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "zugferd-invoice.xml", "xml", false, true);
|
||||
} else {
|
||||
System.out.println("ZUGFeRD 1.0 XML source set to " + outName);
|
||||
}
|
||||
@@ -421,7 +433,7 @@ public class Toecount {
|
||||
}
|
||||
|
||||
private static void performCombine(String pdfName, String xmlName, String outName, String format, String zfVersion,
|
||||
String zfProfile) throws Exception {
|
||||
String zfProfile) throws Exception {
|
||||
/*
|
||||
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
|
||||
* .setProducer("toecount") .setCreator(System.getProperty("user.name"))
|
||||
@@ -459,7 +471,6 @@ public class Toecount {
|
||||
System.out.println("Format set to " + format);
|
||||
}
|
||||
|
||||
|
||||
if (zfVersion == null) {
|
||||
try {
|
||||
zfVersion = getStringFromUser("Version (1 or 2)", "1", "1|2");
|
||||
@@ -473,13 +484,12 @@ public class Toecount {
|
||||
|
||||
if (zfProfile == null) {
|
||||
try {
|
||||
if (format.equals("zf")&&(zfIntVersion == 1)) {
|
||||
zfProfile = getStringFromUser("Profile b)asic, c)omfort or e)xtended", "e",
|
||||
"B|b|C|c|E|e");
|
||||
if (format.equals("zf") && (zfIntVersion == 1)) {
|
||||
zfProfile = getStringFromUser("Profile b)asic, c)omfort or e)xtended", "e", "B|b|C|c|E|e");
|
||||
} else {
|
||||
zfProfile = getStringFromUser(
|
||||
"Profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, E[X]TENDED",
|
||||
"E", "M|m|W|w|B|b|C|c|E|e|X|x|");
|
||||
"Profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, E[X]TENDED", "E",
|
||||
"M|m|W|w|B|b|C|c|E|e|X|x|");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
|
||||
@@ -495,11 +505,11 @@ public class Toecount {
|
||||
ensureFileExists(xmlName);
|
||||
ensureFileNotExists(outName);
|
||||
|
||||
if ((format.equals("fx"))&&(zfIntVersion>1)) {
|
||||
if ((format.equals("fx")) && (zfIntVersion > 1)) {
|
||||
throw new Exception("Factur-X is only available in version 1 (roughly corresponding to ZF2)");
|
||||
}
|
||||
|
||||
if ((format.equals("zf"))&&(zfIntVersion == 1)) {
|
||||
if ((format.equals("zf")) && (zfIntVersion == 1)) {
|
||||
if (zfProfile.equals("b")) {
|
||||
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASIC;
|
||||
} else if (zfProfile.equals("c")) {
|
||||
@@ -509,7 +519,7 @@ public class Toecount {
|
||||
} else {
|
||||
throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile));
|
||||
}
|
||||
} else if (((format.equals("zf"))&&(zfIntVersion == 2))||(format.equals("fx"))) {
|
||||
} else if (((format.equals("zf")) && (zfIntVersion == 2)) || (format.equals("fx"))) {
|
||||
if (zfProfile.equals("m")) {
|
||||
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.MINIMUM;
|
||||
} else if (zfProfile.equals("w")) {
|
||||
@@ -539,7 +549,6 @@ public class Toecount {
|
||||
ze.setFacturX();
|
||||
}
|
||||
|
||||
|
||||
ze.setZUGFeRDXMLData(Files.readAllBytes(Paths.get(xmlName)));
|
||||
|
||||
ze.export(outName);
|
||||
|
||||
3008
src/main/resources/stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt
Normal file
3008
src/main/resources/stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt
Normal file
File diff suppressed because it is too large
Load Diff
65
src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java
Normal file
65
src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.runners.MethodSorters;
|
||||
|
||||
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;
|
||||
|
||||
public class BaseTest extends TestCase {
|
||||
/**
|
||||
* Create the test case
|
||||
*
|
||||
* @param testName name of the test case
|
||||
*/
|
||||
public BaseTest(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the suite of tests being tested
|
||||
*/
|
||||
public static Test suite() {
|
||||
return new TestSuite(BaseTest.class);
|
||||
}
|
||||
|
||||
public void testCorrectDigits() {
|
||||
assertEquals("0.00", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal(0),2));
|
||||
assertEquals("-1.10", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.10"),2));
|
||||
assertEquals("-1.10", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.1"),2));
|
||||
assertEquals("-1.01", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.01"),2));
|
||||
assertEquals("20000123.35", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3489"),2));
|
||||
assertEquals("20000123.34", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3419"),2));
|
||||
assertEquals("12.00", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("12"),2));
|
||||
assertEquals("12", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("12"),0));
|
||||
assertEquals("20000123.342", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3419"),3));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import org.junit.runners.MethodSorters;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class MustangReaderWriterCustomXMLTest extends TestCase {
|
||||
@@ -49,7 +50,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
|
||||
|
||||
// //////// TESTS
|
||||
// //////////////////////////////////////////////////////////////////////////////////////////
|
||||
public void testCustomZF2Export() throws Exception {
|
||||
public void testCustomZF2Export() {
|
||||
|
||||
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506custom.pdf";
|
||||
// the writing part
|
||||
@@ -61,8 +62,10 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
|
||||
.load(SOURCE_PDF);
|
||||
|
||||
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" +
|
||||
/* 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.
|
||||
* test the export with bom (which is valid) because this will also test the import (which also needs to work and needs to be tested)
|
||||
* */
|
||||
String ownZUGFeRDXML = new String(UTF8ByteOrderMark, StandardCharsets.UTF_8) + "<?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" +
|
||||
" <rsm:ExchangedDocumentContext>\n" +
|
||||
" <ram:TestIndicator><udt:Indicator>false</udt:Indicator></ram:TestIndicator>\n" +
|
||||
@@ -286,10 +289,10 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
|
||||
* ./src/test/MustangGnuaccountingBeispielRE-20140703_502blanko.pdf}, adds
|
||||
* metadata, writes to @{code ./target/testout-*} and then imports to check the
|
||||
* values. It would not make sense to have it run before the less complex
|
||||
* importer test (which is probably redundant) --> as only Name Ascending is
|
||||
* importer test (which is probably redundant). As only Name Ascending is
|
||||
* supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export
|
||||
*/
|
||||
public void testCustomZF1Export() throws Exception {
|
||||
public void testCustomZF1Export() {
|
||||
|
||||
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20170509_505custom.pdf";
|
||||
// the writing part
|
||||
|
||||
@@ -170,13 +170,11 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
|
||||
|
||||
/**
|
||||
* The importer test imports from ./src/test/MustangGnuaccountingBeispielRE-20170509_505.pdf to check the values.
|
||||
* --> as only Name Ascending is supported for Test Unit sequence, I renamed the this test-A-Export to run before
|
||||
* As only Name Ascending is supported for Test Unit sequence, I renamed the this test-A-Import to run before
|
||||
* testZExport
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
|
||||
public void testAImport() throws IOException {
|
||||
public void testAImport() {
|
||||
InputStream inputStream = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505.pdf");
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream);
|
||||
|
||||
@@ -195,12 +193,11 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
|
||||
|
||||
/**
|
||||
* The exporter test bases on @{code ./src/test/MustangGnuaccountingBeispielRE-20140703_502blanko.pdf}, adds metadata,
|
||||
* writes
|
||||
* to @{code ./target/testout-*} and then imports to check the values.
|
||||
* It would not make sense to have it run before the less complex importer test (which is probably redundant)
|
||||
* --> as only Name Ascending is supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export
|
||||
* writes to @{code ./target/testout-*} and then imports to check the values.
|
||||
* It would not make sense to have it run before the less complex importer test (which is probably redundant).
|
||||
* As only Name Ascending is supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export
|
||||
*/
|
||||
public void testEdgeExport() throws Exception {
|
||||
public void testEdgeExport() {
|
||||
|
||||
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20170509_505newEdge.pdf";
|
||||
// the writing part
|
||||
@@ -218,6 +215,8 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
|
||||
String theXML = new String(ze.getProvider().getXML());
|
||||
assertTrue(theXML.contains("<rsm:CrossIndustryDocument"));
|
||||
ze.export(TARGET_PDF);
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not happen in testEdgeExport");
|
||||
}
|
||||
|
||||
// now check the contents (like MustangReaderTest)
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.apache.xmpbox.xml.DomXmpParser;
|
||||
import org.apache.xmpbox.xml.XmpParsingException;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.mustangproject.ZUGFeRD.model.DocumentContextParameterTypeConstants;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
@@ -184,15 +185,12 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
||||
// //////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* The importer test imports from
|
||||
* ./src/test/MustangGnuaccountingBeispielRE-20170509_505.pdf to check the
|
||||
* values. --> as only Name Ascending is supported for Test Unit sequence, I
|
||||
* renamed the this test-A-Export to run before testZExport
|
||||
*
|
||||
* @throws IOException
|
||||
* The importer test imports from ./src/test/MustangGnuaccountingBeispielRE-20170509_505.pdf to check the
|
||||
* values. As only Name Ascending is supported for Test Unit sequence, I renamed the this testAImport
|
||||
* to run before testZExport
|
||||
*/
|
||||
|
||||
public void testAImport() throws IOException {
|
||||
public void testAImport() {
|
||||
InputStream inputStream = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505.pdf");
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream);
|
||||
|
||||
@@ -206,7 +204,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
||||
assertEquals(zi.getForeignReference(), "RE-20170509/505");
|
||||
}
|
||||
|
||||
public void testForeignImport() throws IOException {
|
||||
public void testForeignImport() {
|
||||
InputStream inputStream = this.getClass().getResourceAsStream("/zugferd_invoice.pdf");
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream);
|
||||
|
||||
@@ -343,16 +341,16 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
||||
* ./src/test/MustangGnuaccountingBeispielRE-20140703_502blanko.pdf}, adds
|
||||
* metadata, writes to @{code ./target/testout-*} and then imports to check the
|
||||
* values. It would not make sense to have it run before the less complex
|
||||
* importer test (which is probably redundant) --> as only Name Ascending is
|
||||
* importer test (which is probably redundant). As only Name Ascending is
|
||||
* supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export
|
||||
*/
|
||||
public void testZExport() throws Exception {
|
||||
public void testZExport() {
|
||||
|
||||
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506new.pdf";
|
||||
|
||||
// the writing part
|
||||
try (InputStream SOURCE_PDF = this.getClass()
|
||||
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
|
||||
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
|
||||
|
||||
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) {
|
||||
|
||||
@@ -370,6 +368,8 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
||||
// assertFalse(pdfContent.indexOf("<pdfaSchema:prefix>zf</pdfaSchema:prefix>") == -1);
|
||||
// assertFalse(pdfContent.indexOf("urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#") == -1);
|
||||
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not happen in testZExport");
|
||||
}
|
||||
|
||||
// now check the contents (like MustangReaderTest)
|
||||
@@ -385,6 +385,37 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
||||
assertEquals(zi.getForeignReference(), getNumber());
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick and dirty copy of testZExport to check if v1 files contain
|
||||
* the correct profile string when the comfort profile is selected.
|
||||
*/
|
||||
public void testZExportv1Profile() {
|
||||
|
||||
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506new.pdf";
|
||||
|
||||
// the writing part
|
||||
try (InputStream SOURCE_PDF = this.getClass()
|
||||
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
|
||||
|
||||
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(1).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.COMFORT).load(SOURCE_PDF)) {
|
||||
|
||||
ze.PDFattachZugferdFile(this);
|
||||
ze.disableAutoClose(true);
|
||||
ze.export(TARGET_PDF);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ze.export(baos);
|
||||
ze.close();
|
||||
String pdfContent = baos.toString("UTF-8");
|
||||
assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.BASIC) >= 0);
|
||||
assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.EXTENDED) >= 0);
|
||||
assertTrue(pdfContent.indexOf(DocumentContextParameterTypeConstants.COMFORT) >= 0);
|
||||
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not happen in testZExport");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testFXExport() throws Exception {
|
||||
|
||||
@@ -423,11 +454,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
||||
assertEquals(zi.getForeignReference(), getNumber());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* @Test(expected = IndexOutOfBoundsException.class)
|
||||
*/
|
||||
public void testExceptionOnPDF14() throws Exception {
|
||||
public void testExceptionOnPDF14() {
|
||||
|
||||
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20170509_505new.pdf";
|
||||
|
||||
|
||||
@@ -34,6 +34,10 @@ public class ResourceUtilities {
|
||||
|
||||
/**
|
||||
* Loading a File into a String using a certain encoding and file path
|
||||
* @param encoding the charset used in the file
|
||||
* @param path the path to the file
|
||||
* @return the file contents as a String
|
||||
* @throws IOException if the file cannot be read
|
||||
*/
|
||||
public static String readFile(Charset encoding, String path) throws IOException {
|
||||
byte[] content = Files.readAllBytes(Paths.get(path));
|
||||
@@ -42,6 +46,10 @@ public class ResourceUtilities {
|
||||
|
||||
/**
|
||||
* Saving a String as a file to a certain file path
|
||||
* @param encoding the charset used in the file
|
||||
* @param path the path to the file
|
||||
* @param content the contents of the file
|
||||
* @throws FileNotFoundException if the file cannot be found
|
||||
*/
|
||||
public static void saveFile(Charset encoding, String path, String content) throws FileNotFoundException {
|
||||
|
||||
@@ -147,7 +155,7 @@ public class ResourceUtilities {
|
||||
|
||||
/**
|
||||
* To fix the 3 slashes bug for File URI: For example:
|
||||
* file:/C:/work/test.txt -> file:///C:/work/test.txt
|
||||
* file:/C:/work/test.txt gives file:///C:/work/test.txt
|
||||
*
|
||||
* @param u - the File URI
|
||||
* @return the String of the URI
|
||||
|
||||
@@ -41,7 +41,7 @@ import static org.junit.Assert.assertFalse;
|
||||
* will be migrated to <code>src/test/resources/migration/output</code>.
|
||||
* If there is a similar named file as test reference <code>src/test/resources/migration/reference</code> a test
|
||||
* will be triggered for every single file.
|
||||
* <p/>
|
||||
*
|
||||
* Note: Any 'ZUGFeRD1' will be exchanged to 'ZUGFeRD2' during migration and adequate reference will be searched for.
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
|
||||
211
src/test/java/org/mustangproject/ZUGFeRD/ZF2EdgeTest.java
Normal file
211
src/test/java/org/mustangproject/ZUGFeRD/ZF2EdgeTest.java
Normal file
@@ -0,0 +1,211 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.runners.MethodSorters;
|
||||
|
||||
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;
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class ZF2EdgeTest extends MustangReaderTestCase {
|
||||
final String TARGET_PDF = "./target/testout-ZF2newEdge.pdf";
|
||||
|
||||
@Override
|
||||
public Date getDeliveryDate() {
|
||||
return new GregorianCalendar(2017, Calendar.MAY, 7).getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getDueDate() {
|
||||
return new GregorianCalendar(2017, Calendar.MAY, 30).getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getIssueDate() {
|
||||
return new GregorianCalendar(2017, Calendar.MAY, 9).getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNumber() {
|
||||
return "RE-20170509/505";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnCountry() {
|
||||
return "DE";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnLocation() {
|
||||
return "Stadthausen";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnOrganisationName() {
|
||||
return "Bei Spiel GmbH";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnStreet() {
|
||||
return "Ecke 12";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IZUGFeRDExportableContact getOwnContact() {
|
||||
return new SenderContact();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnTaxID() {
|
||||
return "22/815/0815/4";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnVATID() {
|
||||
return "DE136695976";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnZIP() {
|
||||
return "12345";
|
||||
}
|
||||
|
||||
@Override
|
||||
public IZUGFeRDExportableContact getRecipient() {
|
||||
return new RecipientContact();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnOrganisationFullPlaintextInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrency() {
|
||||
return "EUR";
|
||||
}
|
||||
|
||||
@Override
|
||||
public IZUGFeRDExportableItem[] getZFItems() {
|
||||
Item[] allItems = new Item[3];
|
||||
Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR", new BigDecimal("7.000000"));
|
||||
Product balloonProduct = new Product("", "Bestellerweiterung für E&F Umbau", "C62", new BigDecimal("19.000000"));
|
||||
Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000"));
|
||||
|
||||
allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
|
||||
allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct);
|
||||
allItems[2] = new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct);
|
||||
return allItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPaymentTermDescription() {
|
||||
SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
|
||||
return "Zahlbar ohne Abzug bis zum " + germanDateFormat.format(getDueDate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IZUGFeRDAllowanceCharge[] getZFAllowances() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IZUGFeRDAllowanceCharge[] getZFCharges() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReferenceNumber() {
|
||||
return "AB321";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the test case
|
||||
*
|
||||
* @param testName name of the test case
|
||||
*/
|
||||
public ZF2EdgeTest(String testName) {
|
||||
super(testName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the suite of tests being tested
|
||||
*/
|
||||
public static Test suite() {
|
||||
return new TestSuite(ZF2EdgeTest.class);
|
||||
}
|
||||
|
||||
// //////// TESTS //////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* The exporter test bases on @{code ./src/test/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf}, adds metadata,
|
||||
* writes to @{code ./target/testout-*} and then imports to check the values.
|
||||
*/
|
||||
public void testEdgeExport() {
|
||||
|
||||
// the writing part
|
||||
|
||||
try (InputStream SOURCE_PDF =
|
||||
this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
|
||||
|
||||
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory()
|
||||
.setProducer("My Application")
|
||||
.setCreator(System.getProperty("user.name"))
|
||||
.setZUGFeRDVersion(2)
|
||||
.ignorePDFAErrors()
|
||||
.load(SOURCE_PDF)) {
|
||||
ze.setZUGFeRDVersion(1);
|
||||
ze.PDFattachZugferdFile(this);
|
||||
String theXML = new String(ze.getProvider().getXML());
|
||||
assertTrue(theXML.contains("<rsm:CrossIndustryDocument"));
|
||||
ze.export(TARGET_PDF);
|
||||
} catch (IOException e) {
|
||||
fail("IOException should not be raised in testEdgeExport");
|
||||
}
|
||||
|
||||
// now check the contents (like MustangReaderTest)
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
|
||||
|
||||
// Reading ZUGFeRD
|
||||
assertEquals(zi.getAmount(), "571.04");
|
||||
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
|
||||
assertEquals(zi.getBLZ(), getTradeSettlementPayment()[0].getOwnBLZ());
|
||||
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
|
||||
assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto());
|
||||
assertEquals(zi.getHolder(), getOwnOrganisationName());
|
||||
assertEquals(zi.getForeignReference(), getNumber());
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user