Merge pull request #1 from ZUGFeRD/master

Update ZUGFeRD master
This commit is contained in:
HKB-CSS
2020-10-28 12:21:22 +01:00
committed by GitHub
132 changed files with 277167 additions and 55725 deletions

View File

@@ -1,32 +1,77 @@
2.0 todo ## 2.0
- verapdf as prevalidation ### done
- remove jaxb
- visualization? - support for ZF 2.1.1, i.e. "Reference profile" Xrechnung
- factory for xrechnung - ZF 2.1.1 now default (up to 1.7.8 ZF2 could be set but ZF1 was default)
- new sample innvoice - removed jaxb
- complete or discard read into push provider
- validate as library doc
- javadoc export
- prompt for source file for validation has to be pdf
- be able to disable "source pdf set to timeout"
- automated tests zuv/verapdf validate created library test files
- unify loggers
done
- 2.1 now default
- pushprovider - pushprovider
- new xrechnung profile - new xrechnung profile
- visualization? zugferdvisualizer?
- german bank account numbers can no longer be specified (dropped in favor of IBAN and BIC) - german bank account numbers can no longer be specified (dropped in favor of IBAN and BIC)
- factory for xrechnung
- moved to Maven central
- complete or discard read into push provider
- integrates validator - integrates validator
- validator now additionally supports xrechnung - validator now additionally supports xrechnung
- integrates mustangserver
- modular project setup - modular project setup
- getSellerTradePartyAddress (PR #157 ) thanks to aberndt-hub - getSellerTradePartyAddress (PR #157 ) thanks to aberndt-hub
- switched from eclipse to IntelliJ - switched from eclipse to IntelliJ
- added ph-schematron-maven-plugin so that xrechnung xslt can be generated - added ph-schematron-maven-plugin so that xrechnung xslt can be generated
- remove migration - removed migration feature (XSLT upgrade of ZF1)
- be able to recursively validate directories - be able to recursively validate directories
- be able to ignore input pdf errors with -i
- be able to recursively scan directories using validateExpectValid/validateExpectInvalid
- upgraded to verapdf 1.16.1
- support to validate XRechnung 2.0
- added Ghostscript signature
- removal of izugferddate/IZUGFeRDPaymentTerms,IZUGFeRDPaymentDiscountTerms
switch
- change from ZUGFeRDExporter to IZUGFeRDExporter
- switch recipient, shipping address from contact to tradeparty
- switch from profiles to profile
- javadoc export
- have visualizer
- validate as library doc
- unify loggers
- release notes
- new tradeparty class, Contact getOwnContact superseded by TradeParty getSender
- new invoicecorrection class
- order-x xml read support
- automated tests zuv/verapdf validate created library test files
- trans.getTradeSettlementPayment() removed in favor of trans.getTradeSettlement()
- commandline option for no notices
- new features
- additional docs,
- contract id,
- delivery period,
- corrected invoices,
- contacts also for recipients
- absolute and relative allowances and charges on item and document level,
- support contact fax numbers
1.7.7 ### 2.0 still todo
- dont show empty tax number field
- new sample invoice
- *visualizer to work with Extended profile
- *visualizer tests
- *validator not to XR error on ZF files (only notices)
- *from A3 does not seem tow ork see mustangreaderwriteredgetest:testedgeexport
- xmp errors may not show correctly in log
- confirm correct generation from pdf/a3 files zf2edgetest
- *correctiontest exports zf1+zf2?
- *USt 0% wird aus invoice-klasse noch nicht sauber abgefangen
- finalize invoiceimporter
Alpha3 2020-10-24
Alpha2 2020-09-15
Alpha1 2020-08-06
Mustangproject 1.7.8
=====
2020-06-14
- corrected ZF2 gross price
Mustangproject 1.7.7
===== =====
2020-05-26 2020-05-26
@@ -35,7 +80,30 @@ done
- #148 support additional documents for items - #148 support additional documents for items
- #154 german VAT ID may not be used for sellercontact scheme id - #154 german VAT ID may not be used for sellercontact scheme id
1.7.6 Validator 0.9.0
=====
2020-03-24
- ZF 2.1 Schema/Schematrons
- check against URI allowing for different fragments
- #27 wrong exit code
- now context also loggs
- introduced fatal errors. new errors: filename empty (10), xml not extractable (17), En16931 CEN Schematron error (24)
- fail better if -f missing
- validate against CEN 1.3
- corrected invalidation of complete output status for broken pdfs
- mention filename in report
- escape xml in report elements, e.g. < in criterion to become <
- validation element has been removed from pdf info and added as attribute in root, duration is now direct child of info
- file not found and file too small now without filename
- XML pretty print output. (XML report may now contain header <?xml...)
- First XMLUnit tests
- Better Check of XML Validity also against documents which start with comments or not with xml header <?xml...
- prevent accidental CEN EN16931 application on extended profile
- solved issues when XML structures start with comments instead of root node
- added Symtrax signature
Mustangproject 1.7.6
===== =====
2020-02-06 2020-02-06
@@ -45,7 +113,7 @@ done
- allow different currencies also for ZF2 (#150) - allow different currencies also for ZF2 (#150)
- minor correction VAT exemptions - minor correction VAT exemptions
1.7.5 Mustangproject 1.7.5
===== =====
2019-11-05 2019-11-05
@@ -56,7 +124,31 @@ done
- corrected RDF metadata for ZF2 - corrected RDF metadata for ZF2
- default conformance level now EN16931, not extended - default conformance level now EN16931, not extended
1.7.4 Validator 0.8.3
=====
2019-10-20
- #22 rounding errors when applying schematron
- check for 1.0 or 2p0 in RDF, not 1.0 and 2.0 like before
- updated to zf 2.0.1
Validator 0.8.2
=====
2019-10-10
- #22 rounding errors when applying schematron
Validator 0.8.1
=====
2019-09-01
- added Signature pdfMachine
- added check for additional data correctness
- #23 ZF2 basic was incorrectly checked against Minimum/Basic Without lines Schema/Schematron
- Merged -x and -z to -f
- Created ZUGFeRDValidatorClass and MiscValidatorTests for e.g. tests without existing files
Mustangproject 1.7.4
===== =====
2019-08-24 2019-08-24
@@ -67,7 +159,7 @@ done
- #132 Mustangproject does not work w/ Java 11 - #132 Mustangproject does not work w/ Java 11
1.7.3 Mustangproject 1.7.3
===== =====
2019-08-01 2019-08-01
@@ -80,93 +172,149 @@ done
- have unit tests for nDigitFormat #23 - have unit tests for nDigitFormat #23
1.7.2 Mustangproject 1.7.2
===== =====
2019-07-08 2019-07-08
Support BuyerReference (r+w), as well as SpecifiedLegalOrganization (w) and DefinedTradeContact (w) - Support BuyerReference (r+w), as well as SpecifiedLegalOrganization (w) and DefinedTradeContact (w)
use dom4j to format output xml document - use dom4j to format output xml document
corrected some exception logging glitches - corrected some exception logging glitches
upgrade PDFBox to 2.0.15+ - upgrade PDFBox to 2.0.15+
extraction to use proper filename instead of alias #98 - extraction to use proper filename instead of alias #98
NullPointerException in ZUGFeRDImporter.extractLowLevel #96 - NullPointerException in ZUGFeRDImporter.extractLowLevel #96
Removed Bankleitzahl from ZF2 - Removed Bankleitzahl from ZF2
Validator 0.8.0
=====
2019-07-08
1.7.1 - updated Mustang to mitigate #20 zf1 validation does not always return a section
- validate not only against schematron but also against schema files
Validator 0.7.0
=====
2019-05-31
- ZUGFeRD 2 final compatible
- now displaying number of applied and failed rules
- now failing if no rule could be applied at all
- profileoverride option no longer needed
- version dependent checks for profiles (i.e. comfort is not a valid ZF2 profile!)
- allow new ZF2 filename (zugferd-invoice.xml instead ZUGFeRD-invoice.xml)
- more JUnit tests
- include own version number in XML report
Mustangproject 1.7.1
===== =====
2019-05-26 2019-05-26
Corrected EN16931 ZF2 profile name Corrected EN16931 ZF2 profile name
1.7.0 Mustangproject 1.7.0
===== =====
2019-05-05 2019-05-05
Export ZF2 final now seems halfway valid (new filename, new namespace prefixa) - Export ZF2 final now seems halfway valid (new filename, new namespace prefixa)
Migrates profile names in ZF1 to ZF2 migration - Migrates profile names in ZF1 to ZF2 migration
Nullpointerex solved with certain invalid profiles - Nullpointerex solved with certain invalid profiles
Be able to access additional files ("additional data") - Be able to access additional files ("additional data")
Known bugs: src/test/resources/migration/reference/ZUGFeRD2_EXTENDED_Warenrechnung.xml is invalid - Known bugs: src/test/resources/migration/reference/ZUGFeRD2_EXTENDED_Warenrechnung.xml is invalid
Validator 0.6.0
=====
2019-02-15
Factur-X compatible Mention xpath location where the errors occurred JUnit tests new way to collect&handle errors XMP/PDF-A-Schema extension validation
1.6.0 Mustangproject 1.6.0
===== =====
2019-02-03 2019-02-03
Closes #69. - Closes #69.
Corrected EN 16931 XMP Schema Extension header - Corrected EN 16931 XMP Schema Extension header
Can now read xmp metadata via ZUGFeRDImporter getXMP - Can now read xmp metadata via ZUGFeRDImporter getXMP
Exporting valid EN16931 Factur-X when version/profile set to 2/EN16931 mode - Exporting valid EN16931 Factur-X when version/profile set to 2/EN16931 mode
1.5.5 Mustangproject 1.5.5
===== =====
2018-10-22 2018-10-22
Fixes by Indigo744: Issues #66 Commandline: provide a way to set input parameters and #68 Combine with ZUGFeRD v2: NullPointerException - Fixes by Indigo744: Issues #66 Commandline: provide a way to set input parameters and #68 Combine with ZUGFeRD v2: NullPointerException
Fixes #63 PDF/A3 conversion not valid. - Fixes #63 PDF/A3 conversion not valid.
1.5.4 Validator 0.5.0
=====
2018-09-10
- Non-16931 profiles are no longer automatically (but still can be manually) checked
- now writing a log file
- attempt to find out which toolkit created that particular file (issue #2)
- fixing that XML could not be extracted from certain valid PDF/A-3 files (issue #9)
- added --action parameter (has to be validate)
- -f option changes to "-o -z"
- added APL license
- added possibility to check XML files only
- fixing issues with files that contained a UTF8 BOM in the XML content ("Content not allowed in prolog")
- Upgraded VeraPDF-validation from 1.10.5 to 1.12.1
Mustangproject 1.5.4
===== =====
2018-08-29 2018-08-29
Fixed #62 fail gracefully on commandline extraction of XML if none is present. - Fixed #62 fail gracefully on commandline extraction of XML if none is present.
New public function: ZUGFeRDImporter.getUTF8 returns raw XML without Byte Order Mark, if one had been used. - New public function: ZUGFeRDImporter.getUTF8 returns raw XML without Byte Order Mark, if one had been used.
1.5.3 Mustangproject 1.5.3
===== =====
2018-07-20 2018-07-20
Fixed #60 nullpointerexception in ZUGFeRDimporter on some input files - Fixed #60 nullpointerexception in ZUGFeRDimporter on some input files
and #61 missing in maven repo - and #61 missing in maven repo
Now possible to skip parse() and go from zi.extract to e.g. zi.getAmount() - Now possible to skip parse() and go from zi.extract to e.g. zi.getAmount()
Mustangproject 1.5.2
1.5.2
===== =====
2018-06-10 2018-06-10
Fixed #57 commandline not converting PDF from A1 to A3 when adding XML to PDF (-c) Fixed #57 commandline not converting PDF from A1 to A3 when adding XML to PDF (-c)
1.5.1 Validator 0.4.3
=====
2018-03-19
Java 8 capability (fixes issue #8)
Validator 0.4.2
=====
2018-03-11
POJO embedding VeraPDF: unable to solve some severe deployment issues
Validator 0.4.1
=====
2018-02-12
ZUGFeRD 2 public preview EN16931 validation using the schematron files the CEN had published under APL
Mustangproject 1.5.1
===== =====
2018-01-13 2018-01-13
Fixed a major issue with the Maven repository (thanks to Markus Plangg, https://github.com/ZUGFeRD/mustangproject/issues/52) Fixed a major issue with the Maven repository (thanks to Markus Plangg, https://github.com/ZUGFeRD/mustangproject/issues/52)
1.5.0 Mustangproject 1.5.0
===== =====
2017-11-30 2017-11-30
Support for ZUGFeRD 2.0 "public review" part 1. - Support for ZUGFeRD 2.0 "public review" part 1.
Now using factories to create/configure ZUGFeRDExporter. - Now using factories to create/configure ZUGFeRDExporter.
Export is now also possible on OutputStream. - Export is now also possible on OutputStream.
Removed need to call PDFattachZugferdFile(null) or exporter close(); - Removed need to call PDFattachZugferdFile(null) or exporter close();
More unit tests, e.g. for custom xml export, PDF/A Schema extensions. - More unit tests, e.g. for custom xml export, PDF/A Schema extensions.
The command line utility "toecount" is now integrated and the main class so "java -jar mustang-1.5.0.jar" should suffice. - The command line utility "toecount" is now integrated and the main class so "java -jar mustang-1.5.0.jar" should suffice.
It now also features options to combine PDF with XML and upgrade XML files from ZF1 to ZF2. - It now also features options to combine PDF with XML and upgrade XML files from ZF1 to ZF2.
First attempts be able to start with a PDF/A-3 in the first place and better error messages for non-PDF/A-conformance. First attempts be able to start with a PDF/A-3 in the first place and better error messages for non-PDF/A-conformance.
@@ -180,45 +328,59 @@ Further changes:
* invalid a3 #44 * invalid a3 #44
* warn on export #39 * warn on export #39
Validator 0.3.0
=====
2017-07-24
1.4.0 First release as VeraPDF plugin
Mustangproject 1.4.0
===== =====
2017-05-11 2017-05-11
Switched to ZUGFeRD extended, new all-in-one jar including dependencies,
switch to Apache PDFBox 2.0. Some bugfixes. - Switched to ZUGFeRD extended, new all-in-one jar including dependencies,
- switch to Apache PDFBox 2.0. Some bugfixes.
Thanks to AlexanderSchmidt and yankee42. Thanks to AlexanderSchmidt and yankee42.
1.3.1 Mustangproject 1.3.1
===== =====
2016-06-01 2016-06-01
1.3.0 Mustangproject 1.3.0
===== =====
2016-03-15 2016-03-15
Additional checks in the new version facilitate correct usage within your own applications. For example, input data (PDF/A-1) and the sequence of the calls are checked for accuracy. Additional checks in the new version facilitate correct usage within your own applications. For example, input data (PDF/A-1) and the sequence of the calls are checked for accuracy.
A community patch (thanks to Alexander Schmidt) improves the internal functioning and removes the last known bugs. A community patch (thanks to Alexander Schmidt) improves the internal functioning and removes the last known bugs.
1.2.0 Mustangproject 1.2.0
===== =====
2015-10-15 2015-10-15
Compliance to GEFEG and ZUGFeRD Checker. Compliance to GEFEG and ZUGFeRD Checker.
1.1.2 Mustangproject 1.1.2
===== =====
2015-06-15 2015-06-15
The ZUGFeRD-Metadata now conforms to more validators like the Konik Validation Service. As a new feature it is now also possible to create test invoices. The ZUGFeRD-Metadata now conforms to more validators like the Konik Validation Service. As a new feature it is now also possible to create test invoices.
1.1.1 Mustangproject 1.1.1
===== =====
2015-03-31 2015-03-31
Maven and custom xml Maven and custom xml
1.1.0 Mustangproject 1.1.0
===== =====
2014-12-07 2014-12-07
ZUGFeRD 1.0 ZUGFeRD 1.0
1.0.0 Mustangproject 1.0.0
===== =====
2014-05-22 2014-05-22
ZUGFeRD 1.0RC Comfort ZUGFeRD 1.0RC Comfort

View File

@@ -3,14 +3,14 @@
<parent> <parent>
<groupId>org.mustangproject</groupId> <groupId>org.mustangproject</groupId>
<artifactId>core</artifactId> <artifactId>core</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>2.0.0-alpha4-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.zugferd</groupId> <groupId>org.mustangproject</groupId>
<artifactId>Mustang-CLI</artifactId> <artifactId>Mustang-CLI</artifactId>
<name>Mustang commandline tool</name> <name>Mustang commandline tool</name>
<packaging>jar</packaging> <packaging>jar</packaging>
<version>2.0.0-SNAPSHOT</version> <version>2.0.0-alpha4-SNAPSHOT</version>
<repositories> <repositories>
<repository> <repository>
<!-- for jargs --> <!-- for jargs -->
@@ -31,7 +31,7 @@
<dependency> <dependency>
<groupId>org.mustangproject</groupId> <groupId>org.mustangproject</groupId>
<artifactId>validator</artifactId> <artifactId>validator</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>2.0.0-alpha4-SNAPSHOT</version>
<!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with <!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with
mvn install:install-file -Dfile=mustang-1.5.4-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.5.4 -Dpackaging=jar -DgeneratePom=true mvn install:install-file -Dfile=mustang-1.5.4-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.5.4 -Dpackaging=jar -DgeneratePom=true
--> -->
@@ -50,7 +50,7 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.12</version> <version>4.13.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -87,6 +87,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration> <configuration>
<archive> <archive>
<manifest> <manifest>
@@ -163,12 +164,6 @@
<include>**</include> <include>**</include>
</includes> </includes>
</filter> </filter>
<filter>
<artifact>com.sun.xml.bind:jaxb-core</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters> </filters>
</configuration> </configuration>
<executions> <executions>

View File

@@ -18,40 +18,35 @@
*********************************************************************** */ *********************************************************************** */
package org.mustangproject.commandline; package org.mustangproject.commandline;
import java.io.BufferedReader; import com.sanityinc.jargs.CmdLineParser;
import java.io.File; import com.sanityinc.jargs.CmdLineParser.Option;
import java.io.IOException; import org.mustangproject.ZUGFeRD.*;
import java.io.InputStreamReader; import org.mustangproject.validator.Validator;
import org.mustangproject.validator.ZUGFeRDValidator;
import java.io.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.transform.TransformerException;
import org.mustangproject.ZUGFeRD.ZUGFeRDConformanceLevel;
import org.mustangproject.ZUGFeRD.ZUGFeRDExporter;
import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1Factory;
import org.mustangproject.ZUGFeRD.ZUGFeRDImporter;
import org.mustangproject.validator.ZUGFeRDValidator;
/*** /***
* This is the command line interface to mustangproject * This is the command line interface to mustangproject
* *
*/ */
import com.sanityinc.jargs.CmdLineParser; import org.slf4j.LoggerFactory;
import com.sanityinc.jargs.CmdLineParser.Option;
import javax.xml.transform.TransformerException;
public class Main { public class Main {
// build with: /opt/local/bin/mvn clean compile assembly:single private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(Validator.class.getCanonicalName()); // log output
private static void printUsage() { private static void printUsage() {
System.err.println(getUsage()); System.err.println(getUsage());
} }
private static String getUsage() { private static String getUsage() {
return "Usage: --action metrics|combine|extract|a3only|validate [-d,--directory] [-l,--listfromstdin] [-i,--ignore fileextension, PDF/A errors] | [-h,--help] \r\n" return "Usage: --action metrics|combine|extract|a3only|validate|visualize [-d,--directory] [-l,--listfromstdin] [-i,--ignore fileextension, PDF/A errors] | [-h,--help] \r\n"
+ "* merics\n" + " -d, --directory count ZUGFeRD files in directory to be scanned\n" + "* merics\n" + " -d, --directory count ZUGFeRD files in directory to be scanned\n"
+ " If it is a directory, it will recurse.\n" + " If it is a directory, it will recurse.\n"
+ " -l, --listfromstdin count ZUGFeRD files from a list of linefeed separated files on runtime.\n" + " -l, --listfromstdin count ZUGFeRD files from a list of linefeed separated files on runtime.\n"
@@ -60,59 +55,43 @@ public class Main {
+ " [-i, --ignorefileextension] Check for all files (*.*) instead of PDF files only (*.pdf) in metrics, ignore PDF/A input file errors in combine\n" + " [-i, --ignorefileextension] Check for all files (*.*) instead of PDF files only (*.pdf) in metrics, ignore PDF/A input file errors in combine\n"
+ "\n" + "* Merge actions\n" + " extract extract ZUGFeRD PDF to XML file\n" + "\n" + "* Merge actions\n" + " extract extract ZUGFeRD PDF to XML file\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n" + " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n" + " [--source=<filename>]: set input PDF file\n"
+ " [--out <filename>]: set output XML file\n" + " [--out=<filename>]: set output XML file\n"
+ " a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n" + " a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n" + " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n" + " [--source=<filename>]: set input PDF file\n"
+ " [--out <filename>]: set output PDF file\n" + " [--out=<filename>]: set output PDF file\n"
+ " combine combine XML and PDF file to ZUGFeRD PDF file\n" + " combine combine XML and PDF file to ZUGFeRD PDF file\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n" + " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n" + " [--source=<filename>]: set input PDF file\n"
+ " [--source-xml <filename>]: set input XML file\n" + " [--source-xml=<filename>]: set input XML file\n"
+ " [--out <filename>]: set output PDF file\n" + " [--out=<filename>]: set output PDF file\n"
+ " [--format <fx|zf>]: set ZUGFeRD or FacturX\n" + " [--format <fx|zf>]: set ZUGFeRD or FacturX\n"
+ " [--version <1|2>]: set ZUGFeRD version\n" + " [--version <1|2>]: set ZUGFeRD version\n"
+ " [--profile <...>]: set ZUGFeRD profile\n" + " [--profile <...>]: set ZUGFeRD profile\n"
+ " For ZUGFeRD v1: <B>ASIC, <C>OMFORT or <E>XTENDED\n" + " For ZUGFeRD v1: <B>ASIC, <C>OMFORT or EX<T>ENDED\n"
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, E<X>TENDED " + " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, <X>Rechnung, EX<T>ENDED "
+ " validate validate XML or PDF file \n" + " validate validate XML or PDF file \n"
+ " [--no-notices]: refrain from reporting notices\n"
+ " [--logAppend=<text>]: text to be added to log line\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n" + " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: input PDF or XML file\n" + " [--source=<filename>]: input PDF or XML file\n"
+ " validateExpectValid validate directory expecting positive results \n"
+ " [--no-notices]: refrain from reporting notices\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " -d, --directory to check recursively \n"
+ " validateExpectInvalid validate directory expecting negative results \n"
+ " [--no-notices]: refrain from reporting notices\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " -d, --directory to check recursively\n"
+ " visualize convert XML to HTML \n"
; ;
} }
private static void printHelp() { private static void printHelp() {
System.out.println("Mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + " \r\n" System.out.println("Mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + " \r\n"
+ "A Apache Public License library and command line tool for statistics on PDF invoices with\r\n" + "A Apache Public License tool for e-invoices with\r\n"
+ "ZUGFeRD Metadata (http://www.zugferd.org)\r\n" + "\r\n" + getUsage() + "\r\n" + "ZUGFeRD Metadata (http://www.zugferd.org)\r\n" + "\r\n" + getUsage() + "\r\n");
+ "* Count operations\r\n" + "\t-d, --directory\tcount ZUGFeRD files in directory to be scanned\r\n"
+ "\t\tIf it is a directory, it will recurse.\r\n"
+ "\t-l, --listfromstdin\tcount ZUGFeRD files from a list of linefeed separated files on runtime.\r\n"
+ "\t\tIt will start once a blank line has been entered.\r\n" + "\r\n"
+ "\tAdditional parameter for both count operations\r\n"
+ "\t[-i, --ignorefileextension]\tCheck for all files (*.*) instead of PDF files only (*.pdf)\r\n"
+ "\r\n" + "* Merge operations\r\n" + "\t-e, --extract\textract ZUGFeRD PDF to XML file\r\n"
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
+ "\t\t[--source <filename>]: set input PDF file\r\n"
+ "\t\t[--out <filename>]: set output XML file\r\n"
+ "\t-u, --upgrade\tupgrade ZUGFeRD XML to ZUGFeRD 2 XML\r\n"
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
+ "\t\t[--source <filename>]: set input XML ZUGFeRD 1 file\r\n"
+ "\t\t[--out <filename>]: set output XML ZUGFeRD 2 file\r\n"
+ "\t-a, --a3only\tupgrade from PDF/A1 to A3 only (no ZUGFeRD data attached) \r\n"
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
+ "\t\t[--source <filename>]: set input PDF file\r\n"
+ "\t\t[--out <filename>]: set output PDF file\r\n"
+ "\t-c, --combine\tcombine XML and PDF file to ZUGFeRD PDF file\r\n"
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
+ "\t\t[--source <filename>]: set input PDF file\r\n"
+ "\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\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, EX<T>ENDED, <X>Rechnung\r\n");
} }
/** /**
@@ -148,7 +127,7 @@ public class Main {
try { try {
input = buffer.readLine(); input = buffer.readLine();
} catch (IOException e) { } catch (IOException e) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e); LOGGER.error(e.getMessage(), e);
} }
@@ -168,7 +147,7 @@ public class Main {
* *
* @param prompt the text the user is asked * @param prompt the text the user is asked
* @param defaultFilename a default Filename * @param defaultFilename a default Filename
* @param expectedExtension will warn if filename does not match expected file extension * @param expectedExtension will warn if filename does not match expected file extension, "or" possible with e.g. pdf|xml
* @param ensureFileExists will warn if file does NOT exist (for input files) * @param ensureFileExists will warn if file does NOT exist (for input files)
* @param ensureFileNotExists will warn if file DOES exist (for output files) * @param ensureFileNotExists will warn if file DOES exist (for output files)
* @return String * @return String
@@ -185,7 +164,7 @@ public class Main {
try { try {
selectedName = buffer.readLine(); selectedName = buffer.readLine();
} catch (IOException e) { } catch (IOException e) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e); LOGGER.error(e.getMessage(), e);
} }
@@ -194,22 +173,15 @@ public class Main {
selectedName = defaultFilename; selectedName = defaultFilename;
} }
boolean hasCorrectExtension=false;
String[] expectedExtensions=expectedExtension.split("\\|");
for (String currentExtension: expectedExtensions) {
if (selectedName.toLowerCase().endsWith(expectedExtension.toLowerCase())) {
hasCorrectExtension=true;
}
}
// error cases // error cases
if (!selectedName.toLowerCase().endsWith(expectedExtension.toLowerCase())) { if (ensureFileExists) {
System.err.println("Expected " + expectedExtension
+ " extension, this may corrupt your file. Do you still want to continue?(Y|N)");
String selectedAnswer = "";
try {
selectedAnswer = buffer.readLine();
} catch (IOException e) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
}
if (!selectedAnswer.equals("Y") && !selectedAnswer.equals("y")) {
System.err.println("Aborted by user");
System.exit(-1);
}
} else if (ensureFileExists) {
if (fileExists(selectedName)) { if (fileExists(selectedName)) {
fileExistenceOK = true; fileExistenceOK = true;
} else { } else {
@@ -217,6 +189,20 @@ public class Main {
// discard the input, a scanner.reset is not sufficient // discard the input, a scanner.reset is not sufficient
fileExistenceOK = false; fileExistenceOK = false;
} }
} else if (!hasCorrectExtension) {
System.err.println("Expected " + expectedExtension
+ " extension, this may corrupt your file. Do you still want to continue?(Y|N)");
String selectedAnswer = "";
try {
selectedAnswer = buffer.readLine();
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
if (!selectedAnswer.equals("Y") && !selectedAnswer.equals("y")) {
System.err.println("Aborted by user");
System.exit(-1);
}
} else { } else {
fileExistenceOK = true; fileExistenceOK = true;
@@ -252,7 +238,8 @@ public class Main {
Option<String> sourceOption = parser.addStringOption("source"); Option<String> sourceOption = parser.addStringOption("source");
// --out: output file // --out: output file
Option<String> outOption = parser.addStringOption("out"); Option<String> outOption = parser.addStringOption("out");
Option<Boolean> noNoticesOption = parser.addBooleanOption("no-notices");
Option<String> logAppendOption = parser.addStringOption("logAppend");
// Command: Combining PDF and XML // Command: Combining PDF and XML
// --combine // --combine
@@ -275,7 +262,6 @@ public class Main {
// Command: Show metrics from list from stdin // Command: Show metrics from list from stdin
// --listfromstdin // --listfromstdin
Option<Boolean> filesFromStdInOption = parser.addBooleanOption('l', "listfromstdin"); Option<Boolean> filesFromStdInOption = parser.addBooleanOption('l', "listfromstdin");
try { try {
parser.parse(args); parser.parse(args);
} catch (CmdLineParser.OptionException e) { } catch (CmdLineParser.OptionException e) {
@@ -294,6 +280,8 @@ public class Main {
String sourceXMLName = parser.getOptionValue(sourceXmlOption); String sourceXMLName = parser.getOptionValue(sourceXmlOption);
String outName = parser.getOptionValue(outOption); String outName = parser.getOptionValue(outOption);
String format = parser.getOptionValue(formatOption); String format = parser.getOptionValue(formatOption);
Boolean noNotices = parser.getOptionValue(noNoticesOption);
String zugferdVersion = parser.getOptionValue(zugferdVersionOption); String zugferdVersion = parser.getOptionValue(zugferdVersionOption);
String zugferdProfile = parser.getOptionValue(zugferdProfileOption); String zugferdProfile = parser.getOptionValue(zugferdProfileOption);
boolean optionsRecognized=false; boolean optionsRecognized=false;
@@ -312,41 +300,39 @@ public class Main {
} else if ((action!=null)&&(action.equals("a3only"))) { } else if ((action!=null)&&(action.equals("a3only"))) {
performConvert(sourceName, outName); performConvert(sourceName, outName);
optionsRecognized=true; optionsRecognized=true;
} else if ((action!=null)&&(action.equals("visualize"))) {
performVisualization(sourceName, outName);
optionsRecognized=true;
} else if ((action!=null)&&(action.equals("validate"))) { } else if ((action!=null)&&(action.equals("validate"))) {
optionsRecognized=performValidate(sourceName, noNotices!=null&&noNotices, parser.getOptionValue(logAppendOption));
optionsRecognized=performValidate(sourceName);
} else if ((action!=null)&&(action.equals("validateExpectValid"))) { } else if ((action!=null)&&(action.equals("validateExpectValid"))) {
optionsRecognized=performValidateExpect(true, directoryName); optionsRecognized=performValidateExpect(true, directoryName);
} else if ((action!=null)&&(action.equals("validateExpectInvalid"))) { } else if ((action!=null)&&(action.equals("validateExpectInvalid"))) {
optionsRecognized=performValidateExpect(false, directoryName); optionsRecognized=performValidateExpect(false, directoryName);
} else { } else {
// no argument or argument unknown // no argument or argument unknown
printUsage(); printUsage();
System.exit(2); System.exit(2);
} }
} catch (Exception e) { } catch (Exception e) {
LOGGER.error(e.getMessage(), e);
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
System.exit(-1); System.exit(-1);
} }
} }
private static boolean performValidate(String sourceName) { private static boolean performValidate(String sourceName, boolean noNotices, String logAppend) {
boolean optionsRecognized; boolean optionsRecognized;
if (sourceName == null) { if (sourceName == null) {
sourceName = getFilenameFromUser("Source PDF", "invoice.pdf", "pdf", true, false); sourceName = getFilenameFromUser("Source PDF or XML", "invoice.pdf", "pdf|xml", true, false);
} else {
System.out.println("Source PDF set to " + sourceName);
} }
ZUGFeRDValidator zfv=new ZUGFeRDValidator(); ZUGFeRDValidator zfv=new ZUGFeRDValidator();
if ((logAppend!=null)&&(logAppend.length()>0)) {
zfv.setLogAppend(logAppend);
}
if (noNotices) {
zfv.disableNotices();
}
System.out.println(zfv.validate(sourceName)); System.out.println(zfv.validate(sourceName));
optionsRecognized = !zfv.hasOptionsError(); optionsRecognized = !zfv.hasOptionsError();
if (!zfv.wasCompletelyValid()) { if (!zfv.wasCompletelyValid()) {
@@ -398,7 +384,7 @@ public class Main {
ensureFileNotExists(outName); ensureFileNotExists(outName);
// All params are good! continue... // All params are good! continue...
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setAttachZUGFeRDHeaders(false).load(pdfName); ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().convertOnly().load(pdfName);
ze.export(outName); ze.export(outName);
System.out.println("Written to " + outName); System.out.println("Written to " + outName);
@@ -412,7 +398,7 @@ public class Main {
System.out.println("Source PDF set to " + pdfName); System.out.println("Source PDF set to " + pdfName);
} }
if (xmlName == null) { if (xmlName == null) {
xmlName = getFilenameFromUser("ZUGFeRD XML", "ZUGFeRD-invoice.xml", "xml", false, true); xmlName = getFilenameFromUser("ZUGFeRD XML", "factur-x.xml", "xml", false, true);
} else { } else {
System.out.println("ZUGFeRD XML set to " + pdfName); System.out.println("ZUGFeRD XML set to " + pdfName);
} }
@@ -441,8 +427,8 @@ public class Main {
* .loadFromPDFA1("invoice.pdf"); * .loadFromPDFA1("invoice.pdf");
*/ */
try { try {
int zfIntVersion = ZUGFeRDExporter.DefaultZUGFeRDVersion; int zfIntVersion = ZUGFeRDExporterFromA3.DefaultZUGFeRDVersion;
ZUGFeRDConformanceLevel zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED; Profile zfConformanceLevelProfile = Profiles.getByName("EXTENDED");
if (pdfName == null) { if (pdfName == null) {
pdfName = getFilenameFromUser("Source PDF", "invoice.pdf", "pdf", true, false); pdfName = getFilenameFromUser("Source PDF", "invoice.pdf", "pdf", true, false);
@@ -451,7 +437,7 @@ public class Main {
} }
if (xmlName == null) { if (xmlName == null) {
xmlName = getFilenameFromUser("ZUGFeRD XML", "ZUGFeRD-invoice.xml", "xml", true, false); xmlName = getFilenameFromUser("ZUGFeRD XML", "factur-x.xml", "xml", true, false);
} else { } else {
System.out.println("ZUGFeRD XML set to " + xmlName); System.out.println("ZUGFeRD XML set to " + xmlName);
} }
@@ -466,7 +452,7 @@ public class Main {
try { try {
format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD)", "zf", "fx|zf"); format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD)", "zf", "fx|zf");
} catch (Exception e) { } catch (Exception e) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e); LOGGER.error(e.getMessage(), e);
} }
} else { } else {
System.out.println("Format set to " + format); System.out.println("Format set to " + format);
@@ -474,9 +460,9 @@ public class Main {
if (zfVersion == null) { if (zfVersion == null) {
try { try {
zfVersion = getStringFromUser("Version (1 or 2)", Integer.toString(ZUGFeRDExporter.DefaultZUGFeRDVersion), "1|2"); zfVersion = getStringFromUser("Version (1 or 2)", Integer.toString(ZUGFeRDExporterFromA3.DefaultZUGFeRDVersion), "1|2");
} catch (Exception e) { } catch (Exception e) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e); LOGGER.error(e.getMessage(), e);
} }
} else { } else {
System.out.println("Version set to " + zfVersion); System.out.println("Version set to " + zfVersion);
@@ -493,8 +479,7 @@ public class Main {
"M|m|W|w|B|b|C|c|E|e|T|t|X|x|"); "M|m|W|w|B|b|C|c|E|e|T|t|X|x|");
} }
} catch (Exception e) { } catch (Exception e) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e); LOGGER.error(e.getMessage(), e);
} }
} else { } else {
System.out.println("Profile set to " + zfProfile); System.out.println("Profile set to " + zfProfile);
@@ -512,29 +497,29 @@ public class Main {
if ((format.equals("zf")) && (zfIntVersion == 1)) { if ((format.equals("zf")) && (zfIntVersion == 1)) {
if (zfProfile.equals("b")) { if (zfProfile.equals("b")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASIC; zfConformanceLevelProfile = Profiles.getByName("BASIC", zfIntVersion);
} else if (zfProfile.equals("c")) { } else if (zfProfile.equals("c")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.COMFORT; zfConformanceLevelProfile = Profiles.getByName("COMFORT", zfIntVersion);
} else if (zfProfile.equals("e")) { } else if (zfProfile.equals("e")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED; zfConformanceLevelProfile = Profiles.getByName("EXTENDED", zfIntVersion);
} else { } else {
throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile)); 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")) { if (zfProfile.equals("m")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.MINIMUM; zfConformanceLevelProfile = Profiles.getByName("MINIMUM", zfIntVersion);
} else if (zfProfile.equals("w")) { } else if (zfProfile.equals("w")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASICWL; zfConformanceLevelProfile = Profiles.getByName("BASICWL", zfIntVersion);
} else if (zfProfile.equals("b")) { } else if (zfProfile.equals("b")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASIC; zfConformanceLevelProfile = Profiles.getByName("BASIC", zfIntVersion);
} else if (zfProfile.equals("c")) { } else if (zfProfile.equals("c")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.CIUS; zfConformanceLevelProfile = Profiles.getByName("CIUS", zfIntVersion);
} else if (zfProfile.equals("e")) { } else if (zfProfile.equals("e")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EN16931; zfConformanceLevelProfile = Profiles.getByName("EN16931", zfIntVersion);
} else if (zfProfile.equals("t")) { } else if (zfProfile.equals("t")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED; zfConformanceLevelProfile = Profiles.getByName("EXTENDED", zfIntVersion);
} else if (zfProfile.equals("x")) { } else if (zfProfile.equals("x")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.XRECHNUNG; zfConformanceLevelProfile = Profiles.getByName("XRECHNUNG", zfIntVersion);
} else { } else {
throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile)); throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile));
} }
@@ -543,28 +528,27 @@ public class Main {
} }
// All params are good! continue... // All params are good! continue...
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setProducer("Mustang-cli") ZUGFeRDExporterFromA1 ze = (ZUGFeRDExporterFromA1) new ZUGFeRDExporterFromA1().setProducer("Mustang-cli")
.setZUGFeRDVersion(zfIntVersion) .setZUGFeRDVersion(zfIntVersion)
.setCreator(System.getProperty("user.name")).setZUGFeRDConformanceLevel(zfConformanceLevelProfile) .setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile)
.load(pdfName); .load(pdfName);
if (ignoreInputErrors) { if (ignoreInputErrors) {
ze.ignoreA1Errors(); ze.ignorePDFAErrors();
} }
if (format.equals("fx")) { if (!format.equals("fx")) {
ze.setFacturX(); ze.disableFacturX();
} }
ze.setZUGFeRDXMLData(Files.readAllBytes(Paths.get(xmlName))); ze.setXML(Files.readAllBytes(Paths.get(xmlName)));
ze.export(outName); ze.export(outName);
System.out.println("Written to " + outName); System.out.println("Written to " + outName);
} catch (IOException e) { } catch (IOException e) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e); LOGGER.error(e.getMessage(), e);
} }
} }
@@ -606,6 +590,91 @@ public class Main {
System.out.println(sr.getSummaryLine()); System.out.println(sr.getSummaryLine());
} }
private static void performVisualization(String sourceName, String outName) {
// Get params from user if not already defined
if (sourceName == null) {
sourceName = getFilenameFromUser("ZUGFeRD XML source", "factur-x.xml", "xml", true, false);
} else {
System.out.println("ZUGFeRD XML source set to " + sourceName);
}
if (outName == null) {
outName = getFilenameFromUser("HTML target file", "factur-x.html", "html", false, true);
} else {
System.out.println("HTML target set to " + outName);
}
// Verify params
try {
ensureFileExists(sourceName);
ensureFileNotExists(outName);
// stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
String xml = null;
try {
xml = zvi.visualize(sourceName);
Files.write(Paths.get(outName), xml.getBytes());
} catch (FileNotFoundException e) {
LOGGER.error(e.getMessage(), e);
} catch (UnsupportedEncodingException e) {
LOGGER.error(e.getMessage(), e);
} catch (TransformerException e) {
LOGGER.error(e.getMessage(), e);
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
System.out.println("Written to " + outName);
try {
ExportResource("/xrechnung-viewer.css");
ExportResource("/xrechnung-viewer.js");
System.out.println("xrechnung-viewer.css and xrechnung-viewer.js written as well (to local working dir)");
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
/**
* Export a resource embedded into a Jar file to the local file path.
*
* @param resourceName ie.: "/SmartLibrary.dll"
* @return The path to the exported resource
* @throws Exception e.g. if the specified resource does not exist at the specified location
*/
static public String ExportResource(String resourceName) throws Exception {
InputStream stream = null;
OutputStream resStreamOut = null;
String jarFolder;
try {
stream = Main.class.getResourceAsStream(resourceName);//note that each / is a directory down in the "jar tree" been the jar the root of the tree
if(stream == null) {
throw new Exception("Cannot get resource \"" + resourceName + "\" from Jar file.");
}
int readBytes;
byte[] buffer = new byte[4096];
jarFolder = System.getProperty("user.dir");
resStreamOut = new FileOutputStream(jarFolder + resourceName);
while ((readBytes = stream.read(buffer)) > 0) {
resStreamOut.write(buffer, 0, readBytes);
}
} catch (Exception ex) {
throw ex;
} finally {
stream.close();
resStreamOut.close();
}
return jarFolder + resourceName;
}
private static void ensureFileExists(String fileName) throws IOException { private static void ensureFileExists(String fileName) throws IOException {
if (!fileExists(fileName)) { if (!fileExists(fileName)) {
throw new IOException(String.format("File %s does not exists", fileName)); throw new IOException(String.format("File %s does not exists", fileName));

View File

@@ -1,6 +1,7 @@
<configuration> <configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder> <encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder> </encoder>
@@ -24,6 +25,6 @@
<!-- Configure so that it outputs to both console and log file --> <!-- Configure so that it outputs to both console and log file -->
<root level="INFO"> <root level="INFO">
<appender-ref ref="FILE" /> <appender-ref ref="FILE" />
<appender-ref ref="STDOUT" /> <appender-ref ref="STDERR" />
</root> </root>
</configuration> </configuration>

165
Release_Notes.md Normal file
View File

@@ -0,0 +1,165 @@
## Changes
On it's official website you can [download](https://www.mustangproject.org/files/Mustang-CLI-2.0.0-alpha3.jar) a alpha release of Mustang 2.
It integrates the successor of the ZUGFeRD [Validator ZUV](https://github.com/ZUGFeRD/ZUV/) in it's command line tool and can be used as library.
Additionally, the default changed from ZUGFeRD 1 to ZUGFeRD 2.1.1 (previously you had to enable that, now you have to specify that you want to use ZF1 if that's the case), it's now available via Maven Central and additionally to the old Interface-style pullProvider requiring you to implement methods there is now also a "normal", class-orientierted, halfway fluent "Push-Provider". It's describe below, if you are impatient please feel free to have a look at it's tests on https://github.com/ZUGFeRD/mustangproject/blob/master/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java.
This is a preview release, please do not (yet) use it in production.
### Use on command line
`java -jar Mustang-CLI-2.0.0-alpha3.jar --action=combine` embedds a XML into a PDF (A-1) file and exports as PDF/A-3
`java -jar mustang-cli.jar --action=extract` extracts XML from a ZUGFeRD file and
`java -jar mustang-cli.jar --action=validate` validates XML or PDF files.
`java -jar mustang-cli.jar --help` still outputs the parameters which can be used
to for non-interactive (i.e., batch) processing.
The source file parameter for validation changed
from `-f` (ZUV) to the usual `--source`. The following
result codes apply:
| section | meaning |
|---|---|
| 1 | file not found |
| 2 | additional data schema validation fails |
| 3 | xml data not found |
| 4 | schematron rule failed |
| 5 | file too small |
| 6 | VeraPDFException |
| 7 | IOException PDF |
| 8 | File does not look like PDF nor XML (contains neither %PDF nor <?xml) |
| 9 | IOException XML |
| 11 | XMP Metadata: ConformanceLevel not found |
| 12 | XMP Metadata: ConformanceLevel contains invalid value |
| 13 | XMP Metadata: DocumentType not found |
| 14 | XMP Metadata: DocumentType invalid |
| 15 | XMP Metadata: Version not found |
| 16 | XMP Metadata: Version contains invalid value |
| 18 | schema validation failed |
| 19 | XMP Metadata: DocumentFileName contains invalid value |
| 20 | not a pdf |
| 21 | XMP Metadata: DocumentFileName not found") |
| 22 | generic XML validation exception |
| 23 | Not a PDF/A-3 |
| 24 | Issues in CEN EN16931 Schematron Check |
| 25 | Unsupported profile type |
| 26 | No rules matched, XML to minimal? |
| 27 | XRechnung Schematron Check |
### Use as Library
We're now on maven central, please remove the old github repository. Additionally, the following changed
| What | old value | new value |
|---|---|---|
| Group id | org.mustangproject.zugferd | org.mustangproject|
| Artifact ID | mustang | library |
| Version | 1.7.8 | 2.0.0-alpha3 |
If you want you can also embed the validator in your software using validator
as artifact ID. "validator" includes the library functionality but is >20 MB
bigger due to it's dependencies.
### Update from 1.x to 2.0
ZF2 was possible with Mustang 1 but it is default in Mustang 2, so
you will need to `.setZUGFeRDVersion(1)` if you don't want ZUGFeRD 2 files.
`PDFattachZugferdFile` is now called `setTransaction` and instead of
a `ZUGFeRDExporterFromA1Factory` the `ZUGFeRDExporterFromA1` will now return a
a class implementing `IZUGFeRDExporter` instead of a `ZUGFeRDExporter`.
So
```
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.COMFORT).load(SOURCE_PDF)) {
```
changes to
```
IZUGFeRDExporter ze = new ZUGFeRDExporterFromA1().setZUGFeRDVersion(1).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) {
```
The importer can still be used like
```
ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream);
String amount = zi.getAmount();
```
but we are also working on an importer to import into the new invoice class.
### Using the library to create e-invoices
From maven central fetch
```
<dependencies>
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.0.0-alpha3</version>
</dependency>
</dependencies>
```
```
import org.mustangproject.Contact;
import org.mustangproject.Invoice;
import org.mustangproject.Item;
import org.mustangproject.Product;
import org.mustangproject.ZUGFeRD.IZUGFeRDExporter;
import org.mustangproject.ZUGFeRD.Profiles;
import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1;
import java.math.BigDecimal;
import java.util.Date;
public class Main {
public static void main(String[] args) {
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setOwnOrganisationName("My company").setOwnStreet("teststr").setOwnZIP("12345").setOwnLocation("teststadt").setOwnCountry("DE").setOwnTaxID("4711").setOwnVATID("0815").setRecipient(new Contact("Franz Müller", "0177123456", "fmueller@test.com", "teststr.12", "55232", "Entenhausen", "DE")).setNumber("INV/123").addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(0)), new BigDecimal(1.0), new BigDecimal(1.0)));
try {
IZUGFeRDExporter ie = new ZUGFeRDExporterFromA1().load("source.pdf").setZUGFeRDVersion(2).setProfile(Profiles.EN16931);
ie.setProfile(Profiles.EN16931).setTransaction(i).export("target.pdf");
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
### Export XML
A invoice like this
```
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setOwnOrganisationName(orgname).setOwnStreet("teststr").setOwnZIP("55232").setOwnLocation("teststadt").setOwnCountry("DE").setOwnTaxID("4711").setOwnVATID("0815").setRecipient(new Contact("Franz Müller", "0177123456", "fmueller@test.com", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(0)), amount, new BigDecimal(1.0)));
```
can be used to get XML
```
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
zf2p.generateXML(i);
String theXML = new String(zf2p.getXML());
```
or can also be used with setTransaction to generate invoice PDFs straight away.
### Embedding the validator
```
<dependencies>
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>validator</artifactId>
<version>2.0.0-alpha3</version>
</dependency>
</dependencies>
```
```
import org.mustangproject.validator.ZUGFeRDValidator;
public class Main {
public static void main(String[] args) {
ZUGFeRDValidator zfv = new ZUGFeRDValidator();
System.out.println(zfv.validate("/tmp/factur-x.xml"));
}
}
```

View File

@@ -3,7 +3,7 @@
1. build 1. build
as excercise to check if the neccessary tools are there, the build is in a stable state and works on your platform, e.g. download and extract https://github.com/ZUGFeRD/mustangproject/archive/master.zip and run ./mvnw clean package To check if the necessary tools are there, the build is in a stable state and works on your platform, e.g. download and extract https://github.com/ZUGFeRD/mustangproject/archive/master.zip and run ./mvnw clean package
Mvnw is a maven wrapper which will download maven.Maven is the dependency management tool which will download all libraries, their dependencies, and build the whole thing. Mvnw is a maven wrapper which will download maven.Maven is the dependency management tool which will download all libraries, their dependencies, and build the whole thing.
@@ -27,6 +27,20 @@ If you do a pull request, please do a feature branch, e.g. if you are working on
Most of mustang is a library, adding (autmated junit) test cases is often not only the most sustainable but also the fastest way to see if new/changed functionality works. If something is changed so that old test cases break on purpose please do not just remove them but take the time to fix the test cases Most of mustang is a library, adding (autmated junit) test cases is often not only the most sustainable but also the fastest way to see if new/changed functionality works. If something is changed so that old test cases break on purpose please do not just remove them but take the time to fix the test cases
## Architecture
Mustang contains a library to read/write e-invoices,
a validator library
(and can also read/write e-invoices, but is substantially
larger) and a commandline application using the latter
library.
The validator component embeds VeraPDF, a open-source
PDF/A-validator, via maven dependency and uses standard java
checks against schema and ph-schematron for checks against the schematron
to validate the XML part of the invoices.
![architecture of the validator](ZUV-Architektur.svg "Graph of the architecture of the validator component")
## New build ## New build
@@ -46,7 +60,13 @@ can be used as debug configuration goal in Eclipse. In that case you can set bre
## Validate ## Validate
[ZUV](https://github.com/ZUGFeRD/ZUV/) can be used to validate generated files. The former ZUGFeRD VeraPDF [ZUV](https://github.com/ZUGFeRD/ZUV/) validator
is now part of Mustangproject.
The JUnit tests of the validator component will also run through a couple of
test files of the library component.
## Deployment ## Deployment
@@ -59,8 +79,28 @@ As „servers“, enter the following
      <id>github</id>       <id>github</id>
      <password>GITHUB-TOKEN</password>       <password>GITHUB-TOKEN</password>
    </server>     </server>
    <server>
      <id>ossrh</id>
      <username>jstaerk</username>
      <password>JIRA-PASSWORD</password>
    </server>
   </servers>    </servers>
``` ```
Add a profiles section to settings.xml
```
<profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.passphrase>PASSPHRASE</gpg.passphrase>
</properties>
</profile>
</profiles>
```
The whole settings.xml then looks e.g. like this The whole settings.xml then looks e.g. like this
```xml ```xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
@@ -77,15 +117,32 @@ The whole settings.xml then looks e.g. like this
      <id>github</id>       <id>github</id>
      <password>TOKEN</password>       <password>TOKEN</password>
    </server>     </server>
    <server>
      <id>ossrh</id>
      <username>jstaerk</username>
      <password>JIRA-PASSWORD</password>
    </server>
</servers> </servers>
<mirrors/> <mirrors/>
<proxies/> <proxies/>
<profiles/> <profiles>
<profile>
<id>ossrh</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.passphrase>PASSPHRASE</gpg.passphrase>
</properties>
</profile>
</profiles>
<activeProfiles/> <activeProfiles/>
</settings> </settings>
``` ```
The password is generated on github. The TOKEN is generated on github.
Deployment to maven central is described e.g. on [dzone](https://dzone.com/articles/publish-your-artifacts-to-maven-central).
See the following screenshot: See the following screenshot:
@@ -93,6 +150,7 @@ Sign in in GitHub and click on the profile picture -> Settings. Now just generat
![screenshot](development_documentation_screenshot_github_settings.png "Screenshot Github Settings") ![screenshot](development_documentation_screenshot_github_settings.png "Screenshot Github Settings")
The Token-ID is the password. The Token-ID is the password.
## Integrate before release ## Integrate before release
If you added functionality which you need to test in another project before a new version of Mustang is released you can If you added functionality which you need to test in another project before a new version of Mustang is released you can
@@ -113,6 +171,7 @@ Change to the project directory and run
* clean the release with `mvn release:clean` and prepare the release with * clean the release with `mvn release:clean` and prepare the release with
* `mvn release:prepare -DignoreSnapshots=true` and enter the version numbers. * `mvn release:prepare -DignoreSnapshots=true` and enter the version numbers.
* After that is through you can create a new release via `mvn release:perform -Dmaven.java.skip=True`.This will also update the maven repo. * After that is through you can create a new release via `mvn release:perform -Dmaven.java.skip=True`.This will also update the maven repo.
* Experimental: mvn deploy -Dregistry=https://maven.pkg.github.com/ZUGFeRD -Dtoken=GH_TOKEN
![screenshot](development_documentation_screenshot_release.png "Screenshot Release") ![screenshot](development_documentation_screenshot_release.png "Screenshot Release")

View File

@@ -3,13 +3,13 @@
<parent> <parent>
<groupId>org.mustangproject</groupId> <groupId>org.mustangproject</groupId>
<artifactId>core</artifactId> <artifactId>core</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>2.0.0-alpha4-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId> <groupId>org.mustangproject</groupId>
<artifactId>library</artifactId> <artifactId>library</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>2.0.0-alpha4-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>Library to write and read FacturX and ZUGFeRD e-invoices. </name> <name>Library to write and read FacturX and ZUGFeRD e-invoices. </name>
<description>The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs. To write files, a provided PDF/A will be combined with generated or provided XML. <description>The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs. To write files, a provided PDF/A will be combined with generated or provided XML.
@@ -54,7 +54,7 @@
<dependency> <dependency>
<groupId>net.sf.saxon</groupId> <groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId> <artifactId>Saxon-HE</artifactId>
<version>9.8.0-11</version> <version>9.9.0-1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.activation</groupId> <groupId>javax.activation</groupId>
@@ -80,7 +80,7 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.12</version> <version>4.13.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@@ -92,32 +92,19 @@
<dependency> <dependency>
<groupId>org.xmlunit</groupId> <groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId> <artifactId>xmlunit-core</artifactId>
<version>2.6.2</version> <version>2.6.3</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- For Toecount -->
<dependency> <dependency>
<groupId>com.sanityinc</groupId> <groupId>org.xmlunit</groupId>
<artifactId>jargs</artifactId> <artifactId>xmlunit-assertj</artifactId>
<version>2.0-SNAPSHOT</version> <version>2.6.3</version>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<pluginManagement>
<plugins> <plugins>
<plugin><!-- mvn help:effective-pom will otherwise tell it just defaults
to 2.3.2 - which does not release in the maven repo, and neither shows any
error message :-( -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<!-- toecount -->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
@@ -139,60 +126,6 @@
<target>1.8</target> <target>1.8</target>
</configuration> </configuration>
</plugin> </plugin>
<!-- /toecount -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<excludePackageNames>org.mustangproject.ZUGFeRD.model.*</excludePackageNames>
</configuration>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<altDeploymentRepository>internal.repo::default::file://${project.build.directory}/mvn-repo
</altDeploymentRepository>
</configuration>
</plugin>
<plugin>
<groupId>com.github.github</groupId>
<artifactId>site-maven-plugin</artifactId>
<version>0.12</version>
<configuration>
<message>Maven artifacts for ${project.version}</message>
<!-- git commit message -->
<noJekyll>true</noJekyll>
<!-- disable webpage processing -->
<outputDirectory>${project.build.directory}/mvn-repo</outputDirectory>
<!-- matches distribution management repository url above -->
<branch>refs/heads/mvn-repo</branch>
<!-- remote branch name -->
<includes>
<include>**/*</include>
</includes>
<merge>true</merge>
<repositoryName>mustangproject</repositoryName>
<!-- github repo name -->
<repositoryOwner>ZUGFeRD</repositoryOwner>
<!-- github username -->
</configuration>
<executions>
<!-- run site-maven-plugin's 'site' target as part of the build's normal
'deploy' phase -->
<execution>
<goals>
<goal>site</goal>
</goals>
<phase>deploy</phase>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
@@ -261,6 +194,8 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<mailingLists> <mailingLists>
<mailingList> <mailingList>
<name>User List</name> <name>User List</name>

View File

@@ -0,0 +1,22 @@
package org.mustangproject;
import org.mustangproject.ZUGFeRD.IExportableTransaction;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
import java.math.BigDecimal;
public class Allowance extends Charge implements IZUGFeRDAllowanceCharge {
public Allowance() {
}
public Allowance(BigDecimal totalAmount) {
super(totalAmount);
}
@Override
public boolean isCharge() {
return false;
}
}

View File

@@ -0,0 +1,44 @@
package org.mustangproject;
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlementPayment;
public class BankDetails implements IZUGFeRDTradeSettlementPayment {
protected String IBAN, BIC;
public BankDetails(String IBAN, String BIC) {
this.IBAN = IBAN;
this.BIC = BIC;
}
public String getIBAN() {
return IBAN;
}
public BankDetails setIBAN(String IBAN) {
this.IBAN = IBAN;
return this;
}
public String getBIC() {
return BIC;
}
public BankDetails setBIC(String BIC) {
this.BIC = BIC;
return this;
}
@Override
public String getOwnBIC() {
return getBIC();
}
@Override
public String getOwnIBAN() {
return getIBAN();
}
}

View File

@@ -0,0 +1,91 @@
package org.mustangproject;
import org.mustangproject.ZUGFeRD.IAbsoluteValueProvider;
import org.mustangproject.ZUGFeRD.IExportableTransaction;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
import java.math.BigDecimal;
public class Charge implements IZUGFeRDAllowanceCharge {
protected BigDecimal percent = null;
protected BigDecimal totalAmount;
protected BigDecimal taxPercent;
protected String reason;
protected String categoryCode;
public Charge() {
taxPercent=new BigDecimal(0);
}
/***
* creates a item level or invoice level charge
* @param totalAmount (the absolute amount)
*/
public Charge(BigDecimal totalAmount) {
this.totalAmount = totalAmount;
}
public Charge setTotalAmount(BigDecimal totalAmount) {
this.totalAmount = totalAmount;
return this;
}
public Charge setPercent(BigDecimal percent) {
this.percent = percent;
return this;
}
public Charge setTaxPercent(BigDecimal taxPercent) {
this.taxPercent = taxPercent;
return this;
}
@Override
public String getReason() {
return reason;
}
public Charge setReason(String reason) {
this.reason = reason;
return this;
}
@Override
public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) {
if (totalAmount!=null) {
return totalAmount;
} else if (percent!=null) {
return currentItem.getValue().multiply(getPercent().divide(new BigDecimal(100)));
} else {
throw new RuntimeException("Either totalAmount or percent must be set");
}
}
@Override
public BigDecimal getPercent() {
return percent;
}
@Override
public BigDecimal getTaxPercent() {
return taxPercent;
}
@Override
public boolean isCharge() {
return true;
}
public Charge setCategoryCode(String categoryCode) {
this.categoryCode = categoryCode;
return this;
}
}

View File

@@ -1,9 +1,18 @@
package org.mustangproject.ZUGFeRD; package org.mustangproject;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact;
public class Contact implements IZUGFeRDExportableContact { public class Contact implements IZUGFeRDExportableContact {
protected String name,phone,email,zip,street,location,country; protected String name,phone,email,zip,street,location,country;
protected String fax=null;
public Contact(String name, String phone, String email) {
this.name = name;
this.phone = phone;
this.email = email;
}
public Contact(String name, String phone, String email, String street, String zip, String location, String country) { public Contact(String name, String phone, String email, String street, String zip, String location, String country) {
this.name = name; this.name = name;
this.phone = phone; this.phone = phone;
@@ -35,6 +44,16 @@ public class Contact implements IZUGFeRDExportableContact {
return this; return this;
} }
@Override
public String getFax() {
return fax;
}
public Contact setFax(String fax) {
this.fax = fax;
return this;
}
public String getEMail() { public String getEMail() {
return email; return email;
} }
@@ -82,4 +101,5 @@ public class Contact implements IZUGFeRDExportableContact {
this.country = country; this.country = country;
return this; return this;
} }
} }

View File

@@ -0,0 +1,67 @@
package org.mustangproject;
public class FileAttachment {
protected String filename;
protected String mimetype;
protected String relation;
protected String description;
protected byte[] data;
public FileAttachment(String filename, String mimetype, String relation, byte[] data) {
this.filename = filename;
this.mimetype = mimetype;
this.relation = relation;
this.data = data;
description = "Additional file attachment";
}
public String getDescription() {
return description;
}
public FileAttachment setDescription(String description) {
this.description = description;
return this;
}
public String getFilename() {
return filename;
}
public FileAttachment setFilename(String filename) {
this.filename = filename;
return this;
}
public String getMimetype() {
return mimetype;
}
public FileAttachment setMimetype(String mimetype) {
this.mimetype = mimetype;
return this;
}
public String getRelation() {
return relation;
}
public FileAttachment setRelation(String relation) {
this.relation = relation;
return this;
}
public byte[] getData() {
return data;
}
public FileAttachment setData(byte[] data) {
this.data = data;
return this;
}
}

View File

@@ -18,27 +18,35 @@
* <p> * <p>
* ********************************************************************** * **********************************************************************
*/ */
package org.mustangproject.ZUGFeRD; package org.mustangproject;
import org.mustangproject.ZUGFeRD.*;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction { public class Invoice implements IExportableTransaction {
protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownTaxID = null, ownVATID = null, ownForeignOrganisationID = null, ownOrganisationName = null, ownStreet = null, ownZIP = null, ownLocation = null, ownCountry = null, currency = null, paymentTermDescription = null; protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null;
protected Date issueDate = null, dueDate = null, deliveryDate = null; protected Date issueDate = null, dueDate = null, deliveryDate = null;
protected BigDecimal totalPrepaidAmount = null; protected BigDecimal totalPrepaidAmount = null;
protected IZUGFeRDExportableContact ownContact = null, recipient = null, deliveryAddress = null; protected TradeParty sender=null, recipient = null, deliveryAddress = null;
protected ArrayList<IZUGFeRDExportableItem> ZFItems = null; protected ArrayList<IZUGFeRDExportableItem> ZFItems = null;
protected String contractReferencedDocument = null;
protected IZUGFeRDAllowanceCharge[] ZFAllowances = null, ZFCharges = null, ZFLogisticsServiceCharges = null; protected Date occurrenceDateFrom = null;
protected IZUGFeRDTradeSettlement[] getTradeSettlement = null; protected Date occurrenceDateTo = null;
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<IZUGFeRDAllowanceCharge>(),
Charges = new ArrayList<IZUGFeRDAllowanceCharge>(), LogisticsServiceCharges = new ArrayList<IZUGFeRDAllowanceCharge>();
protected IZUGFeRDPaymentTerms paymentTerms = null; protected IZUGFeRDPaymentTerms paymentTerms = null;
public ZUGFeRD2PushProvider() { public Invoice() {
ZFItems = new ArrayList<IZUGFeRDExportableItem>(); ZFItems = new ArrayList<IZUGFeRDExportableItem>();
setCurrency("EUR");
} }
@Override @Override
@@ -46,7 +54,9 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return documentName; return documentName;
} }
public ZUGFeRD2PushProvider setDocumentName(String documentName) { public String getContractReferencedDocument() { return contractReferencedDocument; }
public Invoice setDocumentName(String documentName) {
this.documentName = documentName; this.documentName = documentName;
return this; return this;
} }
@@ -56,27 +66,39 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return documentCode; return documentCode;
} }
public ZUGFeRD2PushProvider setDocumentCode(String documentCode) { public Invoice setDocumentCode(String documentCode) {
this.documentCode = documentCode; this.documentCode = documentCode;
return this; return this;
} }
@Override @Override
public String getNumber() { public String getNumber() {
return number; return number;
} }
public ZUGFeRD2PushProvider setNumber(String number) { public Invoice setNumber(String number) {
this.number = number; this.number = number;
return this; return this;
} }
/***
* switch type to invoice correction and refer to document number
* @param number the invoice number to be corrected
* @return this object (fluent setter)
*/
public Invoice setCorrection(String number) {
setBuyerOrderReferencedDocumentID(number);
documentCode= DocumentCodeTypeConstants.CORRECTEDINVOICE;
return this;
}
@Override @Override
public String getOwnOrganisationFullPlaintextInfo() { public String getOwnOrganisationFullPlaintextInfo() {
return ownOrganisationFullPlaintextInfo; return ownOrganisationFullPlaintextInfo;
} }
public ZUGFeRD2PushProvider setOwnOrganisationFullPlaintextInfo(String ownOrganisationFullPlaintextInfo) { public Invoice setOwnOrganisationFullPlaintextInfo(String ownOrganisationFullPlaintextInfo) {
this.ownOrganisationFullPlaintextInfo = ownOrganisationFullPlaintextInfo; this.ownOrganisationFullPlaintextInfo = ownOrganisationFullPlaintextInfo;
return this; return this;
} }
@@ -86,7 +108,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return referenceNumber; return referenceNumber;
} }
public ZUGFeRD2PushProvider setReferenceNumber(String referenceNumber) { public Invoice setReferenceNumber(String referenceNumber) {
this.referenceNumber = referenceNumber; this.referenceNumber = referenceNumber;
return this; return this;
} }
@@ -96,7 +118,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return shipToOrganisationID; return shipToOrganisationID;
} }
public ZUGFeRD2PushProvider setShipToOrganisationID(String shipToOrganisationID) { public Invoice setShipToOrganisationID(String shipToOrganisationID) {
this.shipToOrganisationID = shipToOrganisationID; this.shipToOrganisationID = shipToOrganisationID;
return this; return this;
} }
@@ -106,7 +128,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return shipToOrganisationName; return shipToOrganisationName;
} }
public ZUGFeRD2PushProvider setShipToOrganisationName(String shipToOrganisationName) { public Invoice setShipToOrganisationName(String shipToOrganisationName) {
this.shipToOrganisationName = shipToOrganisationName; this.shipToOrganisationName = shipToOrganisationName;
return this; return this;
} }
@@ -116,7 +138,9 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return shipToStreet; return shipToStreet;
} }
public ZUGFeRD2PushProvider setShipToStreet(String shipToStreet) {
public Invoice setShipToStreet(String shipToStreet) {
this.shipToStreet = shipToStreet; this.shipToStreet = shipToStreet;
return this; return this;
} }
@@ -126,7 +150,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return shipToZIP; return shipToZIP;
} }
public ZUGFeRD2PushProvider setShipToZIP(String shipToZIP) { public Invoice setShipToZIP(String shipToZIP) {
this.shipToZIP = shipToZIP; this.shipToZIP = shipToZIP;
return this; return this;
} }
@@ -136,7 +160,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return shipToLocation; return shipToLocation;
} }
public ZUGFeRD2PushProvider setShipToLocation(String shipToLocation) { public Invoice setShipToLocation(String shipToLocation) {
this.shipToLocation = shipToLocation; this.shipToLocation = shipToLocation;
return this; return this;
} }
@@ -146,7 +170,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return shipToCountry; return shipToCountry;
} }
public ZUGFeRD2PushProvider setShipToCountry(String shipToCountry) { public Invoice setShipToCountry(String shipToCountry) {
this.shipToCountry = shipToCountry; this.shipToCountry = shipToCountry;
return this; return this;
} }
@@ -156,7 +180,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return buyerOrderReferencedDocumentID; return buyerOrderReferencedDocumentID;
} }
public ZUGFeRD2PushProvider setBuyerOrderReferencedDocumentID(String buyerOrderReferencedDocumentID) { public Invoice setBuyerOrderReferencedDocumentID(String buyerOrderReferencedDocumentID) {
this.buyerOrderReferencedDocumentID = buyerOrderReferencedDocumentID; this.buyerOrderReferencedDocumentID = buyerOrderReferencedDocumentID;
return this; return this;
} }
@@ -166,28 +190,37 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return buyerOrderReferencedDocumentIssueDateTime; return buyerOrderReferencedDocumentIssueDateTime;
} }
public ZUGFeRD2PushProvider setBuyerOrderReferencedDocumentIssueDateTime(String buyerOrderReferencedDocumentIssueDateTime) { public Invoice setBuyerOrderReferencedDocumentIssueDateTime(String buyerOrderReferencedDocumentIssueDateTime) {
this.buyerOrderReferencedDocumentIssueDateTime = buyerOrderReferencedDocumentIssueDateTime; this.buyerOrderReferencedDocumentIssueDateTime = buyerOrderReferencedDocumentIssueDateTime;
return this; return this;
} }
@Override @Override
public String getOwnTaxID() { public String getOwnTaxID() {
return ownTaxID; return getSender().getTaxID();
} }
public ZUGFeRD2PushProvider setOwnTaxID(String ownTaxID) {
this.ownTaxID = ownTaxID; @Deprecated
/***
* @deprecated use TradeParty::addTaxID instead
*/
public Invoice setOwnTaxID(String ownTaxID) {
sender.addTaxID(ownTaxID);
return this; return this;
} }
@Override @Override
public String getOwnVATID() { public String getOwnVATID() {
return ownVATID; return getSender().getVATID();
} }
public ZUGFeRD2PushProvider setOwnVATID(String ownVATID) { @Deprecated
this.ownVATID = ownVATID; /***
* @deprecated use TradeParty::addVATID instead
*/
public Invoice setOwnVATID(String ownVATID) {
sender.addVATID(ownVATID);
return this; return this;
} }
@@ -196,7 +229,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return ownForeignOrganisationID; return ownForeignOrganisationID;
} }
public ZUGFeRD2PushProvider setOwnForeignOrganisationID(String ownForeignOrganisationID) { public Invoice setOwnForeignOrganisationID(String ownForeignOrganisationID) {
this.ownForeignOrganisationID = ownForeignOrganisationID; this.ownForeignOrganisationID = ownForeignOrganisationID;
return this; return this;
} }
@@ -206,55 +239,39 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return ownOrganisationName; return ownOrganisationName;
} }
public ZUGFeRD2PushProvider setOwnOrganisationName(String ownOrganisationName) { public Invoice setOwnOrganisationName(String ownOrganisationName) {
this.ownOrganisationName = ownOrganisationName; this.ownOrganisationName = ownOrganisationName;
return this; return this;
} }
@Override @Override
public String getOwnStreet() { public String getOwnStreet() {
return ownStreet; return sender.getStreet();
} }
public ZUGFeRD2PushProvider setOwnStreet(String ownStreet) {
this.ownStreet = ownStreet;
return this;
}
@Override @Override
public String getOwnZIP() { public String getOwnZIP() {
return ownZIP; return sender.getZIP();
} }
public ZUGFeRD2PushProvider setOwnZIP(String ownZIP) {
this.ownZIP = ownZIP;
return this;
}
public String getOwnLocation() { public String getOwnLocation() {
return ownLocation; return sender.getLocation();
} }
public ZUGFeRD2PushProvider setOwnLocation(String getOwnLocation) {
this.ownLocation = getOwnLocation;
return this;
}
public String getOwnCountry() { public String getOwnCountry() {
return ownCountry; return sender.getCountry();
} }
public ZUGFeRD2PushProvider setOwnCountry(String getOwnCountry) {
this.ownCountry = getOwnCountry;
return this;
}
@Override @Override
public String getCurrency() { public String getCurrency() {
return currency; return currency;
} }
public ZUGFeRD2PushProvider setCurrency(String currency) { public Invoice setCurrency(String currency) {
this.currency = currency; this.currency = currency;
return this; return this;
} }
@@ -264,7 +281,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return paymentTermDescription; return paymentTermDescription;
} }
public ZUGFeRD2PushProvider setPaymentTermDescription(String paymentTermDescription) { public Invoice setPaymentTermDescription(String paymentTermDescription) {
this.paymentTermDescription = paymentTermDescription; this.paymentTermDescription = paymentTermDescription;
return this; return this;
} }
@@ -274,7 +291,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return issueDate; return issueDate;
} }
public ZUGFeRD2PushProvider setIssueDate(Date issueDate) { public Invoice setIssueDate(Date issueDate) {
this.issueDate = issueDate; this.issueDate = issueDate;
return this; return this;
} }
@@ -284,7 +301,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return dueDate; return dueDate;
} }
public ZUGFeRD2PushProvider setDueDate(Date dueDate) { public Invoice setDueDate(Date dueDate) {
this.dueDate = dueDate; this.dueDate = dueDate;
return this; return this;
} }
@@ -294,7 +311,7 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return deliveryDate; return deliveryDate;
} }
public ZUGFeRD2PushProvider setDeliveryDate(Date deliveryDate) { public Invoice setDeliveryDate(Date deliveryDate) {
this.deliveryDate = deliveryDate; this.deliveryDate = deliveryDate;
return this; return this;
} }
@@ -304,86 +321,94 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return totalPrepaidAmount; return totalPrepaidAmount;
} }
public ZUGFeRD2PushProvider setTotalPrepaidAmount(BigDecimal totalPrepaidAmount) { public Invoice setTotalPrepaidAmount(BigDecimal totalPrepaidAmount) {
this.totalPrepaidAmount = totalPrepaidAmount; this.totalPrepaidAmount = totalPrepaidAmount;
return this; return this;
} }
@Override @Override
public IZUGFeRDExportableContact getOwnContact() { public IZUGFeRDExportableTradeParty getSender() {
return ownContact; return sender;
} }
public ZUGFeRD2PushProvider setOwnContact(IZUGFeRDExportableContact ownContact) { public Invoice setOwnContact(Contact ownContact) {
this.ownContact = ownContact; this.sender.setContact(ownContact);
return this; return this;
} }
@Override public IZUGFeRDExportableTradeParty getRecipient() {
public IZUGFeRDExportableContact getRecipient() {
return recipient; return recipient;
} }
public ZUGFeRD2PushProvider setRecipient(IZUGFeRDExportableContact recipient) { public Invoice setRecipient(TradeParty recipient) {
this.recipient = recipient; this.recipient = recipient;
return this; return this;
} }
public Invoice setSender(TradeParty sender) {
this.sender = sender;
if ((sender.getBankDetails()!=null)&&(sender.getBankDetails().size()>0)) {
// convert bankdetails
}
return this;
}
@Override @Override
public IZUGFeRDAllowanceCharge[] getZFAllowances() { public IZUGFeRDAllowanceCharge[] getZFAllowances() {
return ZFAllowances; if (Allowances.isEmpty()) {
return null;
} else
return Allowances.toArray(new IZUGFeRDAllowanceCharge[0]);
} }
public ZUGFeRD2PushProvider setZFAllowances(IZUGFeRDAllowanceCharge[] ZFAllowances) {
this.ZFAllowances = ZFAllowances;
return this;
}
@Override @Override
public IZUGFeRDAllowanceCharge[] getZFCharges() { public IZUGFeRDAllowanceCharge[] getZFCharges() {
return ZFCharges; if (Charges.isEmpty()) {
return null;
} else
return Charges.toArray(new IZUGFeRDAllowanceCharge[0]);
} }
public ZUGFeRD2PushProvider setZFCharges(IZUGFeRDAllowanceCharge[] ZFCharges) {
this.ZFCharges = ZFCharges;
return this;
}
@Override @Override
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() { public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
return ZFLogisticsServiceCharges; if (LogisticsServiceCharges.isEmpty()) {
return null;
} else
return LogisticsServiceCharges.toArray(new IZUGFeRDAllowanceCharge[0]);
} }
public ZUGFeRD2PushProvider setZFLogisticsServiceCharges(IZUGFeRDAllowanceCharge[] ZFLogisticsServiceCharges) {
this.ZFLogisticsServiceCharges = ZFLogisticsServiceCharges; @Override
return this; public IZUGFeRDTradeSettlement[] getTradeSettlement() {
if (getSender()==null) {
return null;
} }
public IZUGFeRDTradeSettlement[] getGetTradeSettlement() { return ((TradeParty)getSender()).getAsTradeSettlement();
return getTradeSettlement;
} }
public ZUGFeRD2PushProvider setGetTradeSettlement(IZUGFeRDTradeSettlement[] getTradeSettlement) {
this.getTradeSettlement = getTradeSettlement;
return this;
}
@Override @Override
public IZUGFeRDPaymentTerms getPaymentTerms() { public IZUGFeRDPaymentTerms getPaymentTerms() {
return paymentTerms; return paymentTerms;
} }
public ZUGFeRD2PushProvider setPaymentTerms(IZUGFeRDPaymentTerms paymentTerms) { public Invoice setPaymentTerms(IZUGFeRDPaymentTerms paymentTerms) {
this.paymentTerms = paymentTerms; this.paymentTerms = paymentTerms;
return this; return this;
} }
@Override @Override
public IZUGFeRDExportableContact getDeliveryAddress() { public TradeParty getDeliveryAddress() {
return deliveryAddress; return deliveryAddress;
} }
public ZUGFeRD2PushProvider setDeliveryAddress(IZUGFeRDExportableContact deliveryAddress) { public Invoice setDeliveryAddress(TradeParty deliveryAddress) {
this.deliveryAddress = deliveryAddress; this.deliveryAddress = deliveryAddress;
return this; return this;
} }
@@ -393,14 +418,20 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
return ZFItems.toArray(new IZUGFeRDExportableItem[0]); return ZFItems.toArray(new IZUGFeRDExportableItem[0]);
} }
public ZUGFeRD2PushProvider addItem(IZUGFeRDExportableItem item) { public Invoice addItem(IZUGFeRDExportableItem item) {
ZFItems.add(item); ZFItems.add(item);
return this; return this;
} }
/***
* checks if all required items are set in order to be able to export it
* @return true if all required items are set
*/
public boolean isValid() { public boolean isValid() {
return (dueDate != null) && (ownZIP != null) && (ownStreet != null) && (ownLocation != null) && (ownCountry != null) && (ownTaxID != null) && (ownVATID != null) && (recipient != null); return (dueDate != null) && (sender != null) && (sender.getTaxID() != null) && (sender.getVATID() != null) && (recipient != null);
//contact //contact
// this.phone = phone; // this.phone = phone;
// this.email = email; // this.email = email;
@@ -410,4 +441,55 @@ public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
// this.country = country; // this.country = country;
} }
public Invoice addCharge(IZUGFeRDAllowanceCharge izac) {
Charges.add(izac);
return this;
}
public Invoice addAllowance(IZUGFeRDAllowanceCharge izac) {
Allowances.add(izac);
return this;
}
public Invoice setContractReferencedDocument(String s) {
contractReferencedDocument=s;
return this;
}
public Invoice setOccurrenceDate(Date occur) {
occurrenceDateFrom=occur;
occurrenceDateTo=null;
return this;
}
public Invoice setOccurrencePeriod(Date start, Date end) {
occurrenceDateFrom=start;
occurrenceDateTo=end;
return this;
}
@Override
public Date getOccurrenceDate() {
return occurrenceDateFrom;
}
@Override
public Date getOccurrencePeriodFrom() {
if (occurrenceDateTo!=null) {
return occurrenceDateFrom;
} else {
return null;
}
}
@Override
public Date getOccurrencePeriodTo() {
if (occurrenceDateTo!=null) {
return occurrenceDateTo;
} else {
return null;
}
}
} }

View File

@@ -1,15 +1,17 @@
package org.mustangproject.ZUGFeRD; package org.mustangproject;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge; import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
public class Item implements IZUGFeRDExportableItem { public class Item implements IZUGFeRDExportableItem {
protected BigDecimal price, quantity, tax, grossPrice, lineTotalAmount; protected BigDecimal price, quantity, tax, grossPrice, lineTotalAmount;
protected String id; protected String id;
protected Product product; protected Product product;
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<IZUGFeRDAllowanceCharge>(),
Charges = new ArrayList<IZUGFeRDAllowanceCharge>();
public Item(Product product, BigDecimal price, BigDecimal quantity) { public Item(Product product, BigDecimal price, BigDecimal quantity) {
this.price = price; this.price = price;
@@ -82,16 +84,32 @@ public class Item implements IZUGFeRDExportableItem {
@Override @Override
public IZUGFeRDAllowanceCharge[] getItemAllowances() { public IZUGFeRDAllowanceCharge[] getItemAllowances() {
if (Allowances.isEmpty()) {
return null; return null;
} else
return Allowances.toArray(new IZUGFeRDAllowanceCharge[0]);
} }
@Override @Override
public IZUGFeRDAllowanceCharge[] getItemCharges() { public IZUGFeRDAllowanceCharge[] getItemCharges() {
if (Charges.isEmpty()) {
return null; return null;
} else
return Charges.toArray(new IZUGFeRDAllowanceCharge[0]);
} }
public Item setProduct(Product product) { public Item setProduct(Product product) {
this.product = product; this.product = product;
return this; return this;
} }
public Item addCharge(IZUGFeRDAllowanceCharge izac) {
Charges.add(izac);
return this;
}
public Item addAllowance(IZUGFeRDAllowanceCharge izac) {
Allowances.add(izac);
return this;
}
} }

View File

@@ -1,4 +1,4 @@
package org.mustangproject.ZUGFeRD; package org.mustangproject;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct;

View File

@@ -0,0 +1,205 @@
package org.mustangproject;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTradeParty;
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlement;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.ArrayList;
public class TradeParty implements IZUGFeRDExportableTradeParty {
protected String name, zip, street, location, country;
protected String taxID = null, vatID = null;
protected String additionalAddress = null;
protected ArrayList<BankDetails> bankDetails = new ArrayList<BankDetails>();
protected Contact contact = null;
public TradeParty(String name, String street, String zip, String location, String country) {
this.name = name;
this.street = street;
this.zip = zip;
this.location = location;
this.country = country;
}
public TradeParty(NodeList nodes) {
/**
* <ram:SellerTradeParty>
* <ram:ID>LIEF-987654321</ram:ID>
* <ram:Name>Max Mustermann IT GmbH</ram:Name>
* <ram:DefinedTradeContact>
* <ram:PersonName>Herr Treudiener</ram:PersonName>
* <ram:TelephoneUniversalCommunication>
* <ram:CompleteNumber>+49 1234-98765-12</ram:CompleteNumber>
* </ram:TelephoneUniversalCommunication>
* <ram:EmailURIUniversalCommunication>
* <ram:URIID>treudiener@max-mustermann-it.de</ram:URIID>
* </ram:EmailURIUniversalCommunication>
* </ram:DefinedTradeContact>
* <ram:PostalTradeAddress>
* <ram:PostcodeCode>12345</ram:PostcodeCode>
* <ram:LineOne>Musterstraße 1</ram:LineOne>
* <ram:CityName>Musterstadt</ram:CityName>
* <ram:CountryID>DE</ram:CountryID>
* </ram:PostalTradeAddress>
* <ram:SpecifiedTaxRegistration>
* <ram:ID schemeID="VA">DE123456789</ram:ID>
* </ram:SpecifiedTaxRegistration>
* </ram:SellerTradeParty>
*/
if (nodes.getLength() > 0) {
for (int nodeIndex = 0; nodeIndex < nodes.getLength(); nodeIndex++) {
//nodes.item(i).getTextContent())) {
Node currentItemNode = nodes.item(nodeIndex);
NodeList itemChilds = currentItemNode.getChildNodes();
for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) {
if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:Name")) {
setName(itemChilds.item(itemChildIndex).getTextContent());
}
if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:PostalTradeAddress")) {
NodeList postal = itemChilds.item(itemChildIndex).getChildNodes();
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
if (postal.item(postalChildIndex).getNodeName().equals("ram:LineOne")) {
setStreet(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getNodeName().equals("ram:LineTwo")) {
setAdditionalAddress(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getNodeName().equals("ram:CityName")) {
setLocation(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getNodeName().equals("ram:PostcodeCode")) {
setZIP(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getNodeName().equals("ram:CountryID")) {
setCountry(postal.item(postalChildIndex).getTextContent());
}
}
}
}
}
}
}
public TradeParty setContact(Contact c) {
this.contact = c;
return this;
}
public TradeParty addBankDetails(BankDetails s) {
bankDetails.add(s);
return this;
}
public ArrayList<BankDetails> getBankDetails() {
return bankDetails;
}
public TradeParty addTaxID(String taxID) {
this.taxID = taxID;
return this;
}
public TradeParty addVATID(String vatID) {
this.vatID = vatID;
return this;
}
@Override
public String getVATID() {
return vatID;
}
@Override
public String getTaxID() {
return taxID;
}
public String getName() {
return name;
}
public TradeParty setName(String name) {
this.name = name;
return this;
}
public String getZIP() {
return zip;
}
public TradeParty setZIP(String zip) {
this.zip = zip;
return this;
}
@Override
public String getStreet() {
return street;
}
public TradeParty setStreet(String street) {
this.street = street;
return this;
}
@Override
public String getLocation() {
return location;
}
public TradeParty setLocation(String location) {
this.location = location;
return this;
}
@Override
public String getCountry() {
return country;
}
public TradeParty setCountry(String country) {
this.country = country;
return this;
}
public String getVatID() {
return vatID;
}
public String getZip() {
return zip;
}
@Override
public IZUGFeRDExportableContact getContact() {
return contact;
}
public IZUGFeRDTradeSettlement[] getAsTradeSettlement() {
if (bankDetails.size() == 0) {
return null;
}
return bankDetails.toArray(new IZUGFeRDTradeSettlement[0]);
}
@Override
public String getAdditionalAddress() {
return additionalAddress;
}
public TradeParty setAdditionalAddress(String additionalAddress) {
this.additionalAddress = additionalAddress;
return this;
}
}

View File

@@ -18,9 +18,10 @@
*********************************************************************** */ *********************************************************************** */
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
public class CustomXMLProvider implements IXMLProvider, IProfileProvider { public class CustomXMLProvider implements IXMLProvider {
protected byte[] zugferdData; protected byte[] zugferdData;
protected Profile profile=Profiles.getByName("EN16931");
@Override @Override
public byte[] getXML() { public byte[] getXML() {
@@ -37,7 +38,7 @@ public class CustomXMLProvider implements IXMLProvider, IProfileProvider {
} }
@Override @Override
public void generateXML(IZUGFeRDExportableTransaction trans) { public void generateXML(IExportableTransaction trans) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@@ -49,13 +50,11 @@ public class CustomXMLProvider implements IXMLProvider, IProfileProvider {
} }
@Override @Override
public String getProfile() { public Profile getProfile() {
// TODO Auto-generated method stub return profile;
return null;
} }
@Override public void setProfile(Profile level) {
public void setProfile(ZUGFeRDConformanceLevel level) { profile=level;
// TODO Auto-generated method stub
} }
} }

View File

@@ -18,10 +18,10 @@
*********************************************************************** */ *********************************************************************** */
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
public interface IProfileProvider { import java.math.BigDecimal;
public String getProfile(); public interface IAbsoluteValueProvider {
public void setProfile(ZUGFeRDConformanceLevel level); public BigDecimal getValue();
} }

View File

@@ -32,7 +32,7 @@ import java.util.Date;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants; import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
public interface IZUGFeRDExportableTransaction { public interface IExportableTransaction {
/** /**
* appears in /rsm:CrossIndustryDocument/rsm:HeaderExchangedDocument/ram:Name * appears in /rsm:CrossIndustryDocument/rsm:HeaderExchangedDocument/ram:Name
@@ -47,7 +47,7 @@ public interface IZUGFeRDExportableTransaction {
/** /**
* *
* *
* @return Code of Document * @return Code number of Document type, e.g. "380" for invoiceF
*/ */
default String getDocumentCode() { default String getDocumentCode() {
return DocumentCodeTypeConstants.INVOICE; return DocumentCodeTypeConstants.INVOICE;
@@ -95,13 +95,17 @@ public interface IZUGFeRDExportableTransaction {
return null; return null;
} }
default String getContractReferencedDocument() {
return null;
}
/** /**
* who processed the order * the sender of the invoice
* *
* @return the contact person at the supplier side * @return the contact person at the supplier side
*/ */
default IZUGFeRDExportableContact getOwnContact() { default IZUGFeRDExportableTradeParty getSender() {
return null; return null;
} }
@@ -133,7 +137,7 @@ public interface IZUGFeRDExportableTransaction {
* *
* @return the recipient of the invoice * @return the recipient of the invoice
*/ */
IZUGFeRDExportableContact getRecipient(); IZUGFeRDExportableTradeParty getRecipient();
/** /**
@@ -161,8 +165,12 @@ public interface IZUGFeRDExportableTransaction {
* @return Tax ID (not VAT ID) of the sender * @return Tax ID (not VAT ID) of the sender
*/ */
default String getOwnTaxID() { default String getOwnTaxID() {
if (getSender()!=null) {
return getSender().getTaxID();
} else {
return null; return null;
} }
}
/** /**
@@ -171,8 +179,12 @@ public interface IZUGFeRDExportableTransaction {
* @return VAT ID (Umsatzsteueridentifikationsnummer) of the sender * @return VAT ID (Umsatzsteueridentifikationsnummer) of the sender
*/ */
default String getOwnVATID() { default String getOwnVATID() {
if (getSender()!=null) {
return getSender().getVATID();
} else {
return null; return null;
} }
}
/** /**
@@ -191,8 +203,12 @@ public interface IZUGFeRDExportableTransaction {
* @return the sender's organisation name * @return the sender's organisation name
*/ */
default String getOwnOrganisationName() { default String getOwnOrganisationName() {
if (getSender()!=null) {
return getSender().getName();
} else {
return null; return null;
} }
}
/** /**
@@ -201,8 +217,12 @@ public interface IZUGFeRDExportableTransaction {
* @return sender street address * @return sender street address
*/ */
default String getOwnStreet() { default String getOwnStreet() {
if (getSender()!=null) {
return getSender().getStreet();
} else {
return null; return null;
} }
}
/** /**
@@ -211,9 +231,14 @@ public interface IZUGFeRDExportableTransaction {
* @return sender postal code * @return sender postal code
*/ */
default String getOwnZIP() { default String getOwnZIP() {
if (getSender()!=null) {
return getSender().getZIP();
} else {
return null; return null;
} }
}
/** /**
* own city * own city
@@ -221,9 +246,14 @@ public interface IZUGFeRDExportableTransaction {
* @return the invoice sender's city * @return the invoice sender's city
*/ */
default String getOwnLocation() { default String getOwnLocation() {
if (getSender()!=null) {
return getSender().getLocation();
} else {
return null; return null;
} }
}
/** /**
* own two digit country code * own two digit country code
@@ -231,9 +261,14 @@ public interface IZUGFeRDExportableTransaction {
* @return the invoice senders two character country iso code * @return the invoice senders two character country iso code
*/ */
default String getOwnCountry() { default String getOwnCountry() {
if (getSender()!=null) {
return getSender().getCountry();
} else {
return null; return null;
} }
}
/** /**
* get delivery date * get delivery date
@@ -242,16 +277,6 @@ public interface IZUGFeRDExportableTransaction {
*/ */
Date getDeliveryDate(); Date getDeliveryDate();
/**
* get delivery date in more specific form. If this and getDeliveryDate() are
* specified, this value will be taken
*
* @return instance holding date and format
*/
default IZUGFeRDDate getZFDeliveryDate() {
return null;
}
/** /**
* get main invoice currency used on the invoice * get main invoice currency used on the invoice
@@ -276,7 +301,7 @@ public interface IZUGFeRDExportableTransaction {
* get payment terms. if set, getPaymentTermDescription() and getDueDate() are * get payment terms. if set, getPaymentTermDescription() and getDueDate() are
* ignored * ignored
* *
* @return * @return the IZUGFeRDPaymentTerms of the invoice
*/ */
default IZUGFeRDPaymentTerms getPaymentTerms() { default IZUGFeRDPaymentTerms getPaymentTerms() {
return null; return null;
@@ -285,7 +310,7 @@ public interface IZUGFeRDExportableTransaction {
/** /**
* returns if a rebate agreements exists * returns if a rebate agreements exists
* *
* @return * @return true if a agreement exists
*/ */
default boolean rebateAgreementExists() { default boolean rebateAgreementExists() {
return false; return false;
@@ -393,10 +418,23 @@ public interface IZUGFeRDExportableTransaction {
/*** /***
* delivery address, i.e. ram:ShipToTradeParty (only supported for zf2) * delivery address, i.e. ram:ShipToTradeParty (only supported for zf2)
* @return * @return the IZUGFeRDExportableTradeParty delivery address
*/ */
default IZUGFeRDExportableContact getDeliveryAddress() { default IZUGFeRDExportableTradeParty getDeliveryAddress() {
return null; return null;
} }
default Date getOccurrenceDate() {
return null;
}
default Date getOccurrencePeriodFrom() {
return null;
}
default Date getOccurrencePeriodTo() {
return null;
}
} }

View File

@@ -18,11 +18,14 @@
*********************************************************************** */ *********************************************************************** */
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
public class ZUGFeRDExporterFromA1Factory extends ZUGFeRDExporterFromA3Factory implements IExporterFactory { public interface IExporter {
public ZUGFeRDExporterFromA1Factory() {
ensurePDFisUpgraded = true; public IExporter setTransaction(IExportableTransaction trans) throws IOException;
public void export(String ZUGFeRDfilename) throws IOException;
} public void export(OutputStream output) throws IOException;
} }

View File

@@ -24,6 +24,11 @@ public interface IXMLProvider {
public void setTest(); public void setTest();
public void generateXML(IZUGFeRDExportableTransaction trans); public void generateXML(IExportableTransaction trans);
public void setProfile(Profile p);
public Profile getProfile();
} }

View File

@@ -24,7 +24,8 @@ import java.math.BigDecimal;
*/ */
public interface IZUGFeRDAllowanceCharge { public interface IZUGFeRDAllowanceCharge {
BigDecimal getTotalAmount(); BigDecimal getTotalAmount(IAbsoluteValueProvider trans);
default BigDecimal getPercent() {return null;}
String getReason(); String getReason();
@@ -34,4 +35,5 @@ public interface IZUGFeRDAllowanceCharge {
return TaxCategoryCodeTypeConstants.STANDARDRATE; return TaxCategoryCodeTypeConstants.STANDARDRATE;
} }
public boolean isCharge();
} }

View File

@@ -1,13 +0,0 @@
package org.mustangproject.ZUGFeRD;
import java.util.Date;
public interface IZUGFeRDDate {
Date getDate();
default ZUGFeRDDateFormat getFormat() {
return ZUGFeRDDateFormat.DATE;
}
}

View File

@@ -38,24 +38,6 @@ public interface IZUGFeRDExportableContact {
return null; 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 * First and last name of the recipient
@@ -74,6 +56,10 @@ public interface IZUGFeRDExportableContact {
return null; return null;
} }
default String getFax() {
return null;
}
/** /**
* Postal code of the recipient * Postal code of the recipient

View File

@@ -30,7 +30,7 @@ import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
import java.math.BigDecimal; import java.math.BigDecimal;
public interface IZUGFeRDExportableItem { public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
IZUGFeRDExportableProduct getProduct(); IZUGFeRDExportableProduct getProduct();
@@ -46,6 +46,10 @@ public interface IZUGFeRDExportableItem {
*/ */
BigDecimal getPrice(); BigDecimal getPrice();
@Override
default BigDecimal getValue() {
return getPrice();
}
/** /**
* how many get billed * how many get billed
* *

View File

@@ -0,0 +1,142 @@
/** **********************************************************************
*
* 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 org.mustangproject.TradeParty;
/**
* Mustangproject's ZUGFeRD implementation neccessary interface for ZUGFeRD exporter Licensed under the APLv2
*
* @author jstaerk
* @version 2.0.0
* dated 2020-09-12
*/
public interface IZUGFeRDExportableTradeParty {
/**
* customer identification assigned by the seller
*
* @return customer identification
*/
default String getID() {
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;
}
default IZUGFeRDExportableContact getContact() {
return null;
}
/**
* First and last name of the recipient
*
* @return First and last name of the recipient
*/
default String getName() {
return null;
}
/**
* Postal code of the recipient
*
* @return Postal code of the recipient
*/
default String getZIP() {
return null;
}
/**
* VAT ID (Umsatzsteueridentifikationsnummer) of the contact
*
* @return VAT ID (Umsatzsteueridentifikationsnummer) of the contact
*/
default String getVATID() {
return null;
}
/**
* two-letter country code of the contact
*
* @return two-letter iso country code of the contact
*/
default String getCountry() {
return null;
}
/**
* Returns the city of the contact
*
* @return Returns the city of the recipient
*/
default String getLocation() {
return null;
}
/**
* Returns the street address (street+number) of the contact
*
* @return street address (street+number) of the contact
*/
default String getStreet() {
return null;
}
/**
* returns additional address information which is display in xml tag "LineTwo"
*
* @return additional address information
*/
default String getAdditionalAddress() {
return null;
}
/***
* obligatory for sender but not for recipient
* @return the tax id as string
*/
default String getTaxID() {
return null;
}
}

View File

@@ -18,10 +18,12 @@
*********************************************************************** */ *********************************************************************** */
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import javax.activation.DataSource;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
public interface IExporterFactory { public interface IZUGFeRDExporter extends Closeable, IExporter {
/** /**
* factory: loads a PDF file and returns an appropriate exporter * factory: loads a PDF file and returns an appropriate exporter
* *
@@ -29,7 +31,7 @@ public interface IExporterFactory {
* @return the generated exporter * @return the generated exporter
* @throws IOException if anything is wrong with filename * @throws IOException if anything is wrong with filename
*/ */
public ZUGFeRDExporter load(String pdfFilename) throws IOException; public IZUGFeRDExporter load(String pdfFilename) throws IOException;
/** /**
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the * Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
@@ -39,7 +41,7 @@ public interface IExporterFactory {
* @return the generated exporter * @return the generated exporter
* @throws IOException (should not happen at all) * @throws IOException (should not happen at all)
*/ */
public ZUGFeRDExporter load(byte[] pdfBinary) throws IOException; public IZUGFeRDExporter load(byte[] pdfBinary) throws IOException;
/** /**
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the * Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
@@ -49,18 +51,18 @@ public interface IExporterFactory {
* @throws IOException if anything is wrong with inputstream * @throws IOException if anything is wrong with inputstream
* @return the generated ZUGFeRDExporter * @return the generated ZUGFeRDExporter
*/ */
public ZUGFeRDExporter load(InputStream pdfSource) throws IOException; public IZUGFeRDExporter load(InputStream pdfSource) throws IOException;
public IZUGFeRDExporter setCreator(String creator);
public IExporterFactory setCreator(String creator); public IZUGFeRDExporter setConformanceLevel(PDFAConformanceLevel newLevel);
public IZUGFeRDExporter setProducer(String producer);
public IExporterFactory setConformanceLevel(PDFAConformanceLevel newLevel); public IZUGFeRDExporter setZUGFeRDVersion(int version);
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException;
public IExporterFactory setProducer(String producer); public IZUGFeRDExporter setXML(byte[] zugferdData) throws IOException;
public IZUGFeRDExporter disableFacturX();
public IExporterFactory setZUGFeRDVersion(int version); // public IZUGFeRDExporter setProfile(Profile zugferdConformanceLevel);
public String getNamespaceForVersion(int ver);
public IExporterFactory ignorePDFAErrors(); public String getPrefixForVersion(int ver) ;
public IZUGFeRDExporter disableAutoClose(boolean disableAutoClose);
public IExporterFactory setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zugferdConformanceLevel); public IXMLProvider getProvider();
} }

View File

@@ -1,12 +1,13 @@
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date;
public interface IZUGFeRDPaymentDiscountTerms { public interface IZUGFeRDPaymentDiscountTerms {
BigDecimal getCalculationPercentage(); BigDecimal getCalculationPercentage();
IZUGFeRDDate getBaseDate(); Date getBaseDate();
int getBasePeriodMeasure(); int getBasePeriodMeasure();

View File

@@ -1,10 +1,12 @@
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import java.util.Date;
public interface IZUGFeRDPaymentTerms { public interface IZUGFeRDPaymentTerms {
String getDescription(); String getDescription();
IZUGFeRDDate getDueDate(); Date getDueDate();
IZUGFeRDPaymentDiscountTerms getDiscountTerms(); IZUGFeRDPaymentDiscountTerms getDiscountTerms();
} }

View File

@@ -28,13 +28,13 @@ public interface IZUGFeRDTradeSettlementDebit extends IZUGFeRDTradeSettlement {
String xml = " <ram:SpecifiedTradeSettlementPaymentMeans>\n" //$NON-NLS-1$ String xml = " <ram:SpecifiedTradeSettlementPaymentMeans>\n"
+ " <ram:TypeCode>59</ram:TypeCode>\n" //$NON-NLS-1$ + " <ram:TypeCode>59</ram:TypeCode>\n"
+ " <ram:PayerPartyDebtorFinancialAccount>\n" //$NON-NLS-1$ + " <ram:PayerPartyDebtorFinancialAccount>\n"
+ " <ram:IBANID>"+XMLTools.encodeXML(getIBAN())+"</ram:IBANID>\n" //$NON-NLS-1$ + " <ram:IBANID>"+XMLTools.encodeXML(getIBAN())+"</ram:IBANID>\n"
+ " </ram:PayerPartyDebtorFinancialAccount>\n"; //$NON-NLS-1$ + " </ram:PayerPartyDebtorFinancialAccount>\n";
xml = xml + " </ram:SpecifiedTradeSettlementPaymentMeans>\n"; //$NON-NLS-1$ xml = xml + " </ram:SpecifiedTradeSettlementPaymentMeans>\n";
return xml; return xml;
} }

View File

@@ -43,26 +43,6 @@ public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement
} }
/**
* BLZ of the sender
*
* @return the BLZ code of the recipient sender's bank
*/
default String getOwnBLZ() {
return null;
}
/**
* Bank name of the sender
*
* @return the name of the sender's bank
*/
default String getOwnBankName() {
return null;
}
/** /**
* IBAN of the sender * IBAN of the sender
* *
@@ -73,32 +53,19 @@ public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement
} }
/**
* IBAN of the sender
*
* @return the Account Number of the invoice sender's bank account
*/
default String getOwnKto() {
return null;
}
default String getSettlementXML() { default String getSettlementXML() {
String xml = " <ram:SpecifiedTradeSettlementPaymentMeans>\n" //$NON-NLS-1$ String xml = " <ram:SpecifiedTradeSettlementPaymentMeans>\n"
+ " <ram:TypeCode>42</ram:TypeCode>\n" //$NON-NLS-1$ + " <ram:TypeCode>42</ram:TypeCode>\n"
+ " <ram:Information>Überweisung</ram:Information>\n" //$NON-NLS-1$ + " <ram:Information>Überweisung</ram:Information>\n"
+ " <ram:PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$ + " <ram:PayeePartyCreditorFinancialAccount>\n"
+ " <ram:IBANID>" + XMLTools.encodeXML(getOwnIBAN()) + "</ram:IBANID>\n"; //$NON-NLS-1$ //$NON-NLS-2$ + " <ram:IBANID>" + XMLTools.encodeXML(getOwnIBAN()) + "</ram:IBANID>\n"; //$NON-NLS-2$
if (getOwnKto()!=null) { xml+= " </ram:PayeePartyCreditorFinancialAccount>\n"
xml+= " <ram:ProprietaryID>" + XMLTools.encodeXML(getOwnKto()) + "</ram:ProprietaryID>\n"; //$NON-NLS-1$ //$NON-NLS-2$ + " <ram:PayeeSpecifiedCreditorFinancialInstitution>\n"
+ " <ram:BICID>" + XMLTools.encodeXML(getOwnBIC()) + "</ram:BICID>\n" //$NON-NLS-2$
} // + " <ram:Name>"+trans.getOwnBankName()+"</ram:Name>\n"
xml+= " </ram:PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
+ " <ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
+ " <ram:BICID>" + XMLTools.encodeXML(getOwnBIC()) + "</ram:BICID>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <ram:Name>"+trans.getOwnBankName()+"</ram:Name>\n" //$NON-NLS-1$
// //$NON-NLS-2$ // //$NON-NLS-2$
+ " </ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$ + " </ram:PayeeSpecifiedCreditorFinancialInstitution>\n"
+ " </ram:SpecifiedTradeSettlementPaymentMeans>\n"; //$NON-NLS-1$ + " </ram:SpecifiedTradeSettlementPaymentMeans>\n";
return xml; return xml;
} }

View File

@@ -4,19 +4,40 @@ import java.math.BigDecimal;
public class LineCalc { public class LineCalc {
private BigDecimal totalGross; private BigDecimal totalGross;
private BigDecimal price;
private BigDecimal priceGross; private BigDecimal priceGross;
private BigDecimal itemTotalNetAmount; private BigDecimal itemTotalNetAmount;
private BigDecimal itemTotalVATAmount; private BigDecimal itemTotalVATAmount;
private BigDecimal allowance = new BigDecimal(0);
private BigDecimal charge = new BigDecimal(0);
public LineCalc(IZUGFeRDExportableItem currentItem) { public LineCalc(IZUGFeRDExportableItem currentItem) {
if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
for (IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
addAllowance(allowance.getTotalAmount(currentItem));
}
}
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
for (IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
addCharge(charge.getTotalAmount(currentItem));
}
}
BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100)) BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100))
.add(new BigDecimal(1)); .add(new BigDecimal(1));
priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159 priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159
totalGross = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity()) price = priceGross.subtract(allowance).add(charge);
totalGross = currentItem.getQuantity().multiply(getPrice()).divide(currentItem.getBasisQuantity())
.multiply(multiplicator); .multiply(multiplicator);
itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity()) itemTotalNetAmount = currentItem.getQuantity().multiply(getPrice()).divide(currentItem.getBasisQuantity())
.setScale(2, BigDecimal.ROUND_HALF_UP); .setScale(2, BigDecimal.ROUND_HALF_UP);
itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount); itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount);
}
public BigDecimal getPrice() {
return price;
} }
public BigDecimal getItemTotalNetAmount() { public BigDecimal getItemTotalNetAmount() {
@@ -28,12 +49,20 @@ public class LineCalc {
} }
public BigDecimal getItemTotalGrossAmount() { public BigDecimal getItemTotalGrossAmount() {
return itemTotalVATAmount; return itemTotalNetAmount;
} }
public BigDecimal getPriceGross() { public BigDecimal getPriceGross() {
return priceGross; return priceGross;
} }
public void addAllowance(BigDecimal b) {
allowance = allowance.add(b);
}
public void addCharge(BigDecimal b) {
charge = charge.add(b);
}
} }

View File

@@ -0,0 +1,28 @@
package org.mustangproject.ZUGFeRD;
public class Profile {
protected String name, id;
public Profile(String name, String ID) {
this.name = name;
this.id = ID;
}
public String getName() {
return name;
}
public String getID() {
return id;
}
public String getXMPName() {
if (name.equals("BASICWL")) {
return "BASIC WL";
} else if (name.equals("EN16931")) {
return "EN 16931";
} else {
return name;
}
}
}

View File

@@ -0,0 +1,62 @@
/**
* *********************************************************************
* <p>
* Copyright 2018 Jochen Staerk
* <p>
* Use is subject to license terms.
* <p>
* 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.
* <p>
* 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.
* <p>
* See the License for the specific language governing permissions and
* limitations under the License.
* <p>
* **********************************************************************
*/
package org.mustangproject.ZUGFeRD;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Profiles {
static Map<String, Profile> zf2Map = Stream.of(new Object[][]{
{"MINIMUM", new Profile("MINIMUM", "urn:factur-x.eu:1p0:minimum")},
{"BASICWL", new Profile("BASICWL", "urn:factur-x.eu:1p0:basicwl")},
{"BASIC", new Profile("BASIC", "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic")},
{"EN16931", new Profile("EN16931", "urn:cen.eu:en16931:2017")},
{"EXTENDED", new Profile("EXTENDED", "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended")},
{"XRECHNUNG", new Profile("XRECHNUNG", "XRECHNUNG")}
}).collect(Collectors.toMap(data -> (String) data[0], data -> (Profile) data[1]));
static Map<String, Profile> zf1Map = Stream.of(new Object[][]{
{"BASIC", new Profile("BASIC", "urn:ferd:CrossIndustryDocument:invoice:1p0:basic")},
{"COMFORT", new Profile("COMFORT", "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort")},
{"EXTENDED", new Profile("EXTENDED", "urn:ferd:CrossIndustryDocument:invoice:1p0:extended")},
}).collect(Collectors.toMap(data -> (String) data[0], data -> (Profile) data[1]));
public static Profile getByName(String name, int version) {
Profile result=null;
if (version==1) {
result=zf1Map.get(name.toUpperCase());
} else {
result=zf2Map.get(name.toUpperCase());
}
if (result==null) { throw new RuntimeException("Profile not found"); }
return result;
}
public static Profile getByName(String name) {
return getByName(name, ZUGFeRDExporterFromA3.DefaultZUGFeRDVersion);
}
}

View File

@@ -56,6 +56,7 @@ public class VATAmount {
public void setBasis(BigDecimal basis) { public void setBasis(BigDecimal basis) {
this.basis = basis; this.basis = basis;
} }
public BigDecimal getCalculated() { public BigDecimal getCalculated() {

View File

@@ -53,7 +53,7 @@ public class XMPSchemaPDFAExtensions extends PDFAExtensionSchema {
public String namespace = null; public String namespace = null;
public String prefix = null; public String prefix = null;
protected ZUGFeRDExporter exporter; protected IZUGFeRDExporter exporter;
protected void setZUGFeRDVersion(int ver) { protected void setZUGFeRDVersion(int ver) {
@@ -89,14 +89,14 @@ public class XMPSchemaPDFAExtensions extends PDFAExtensionSchema {
return li; return li;
} }
public XMPSchemaPDFAExtensions(ZUGFeRDExporter ze, XMPMetadata metadata, int ZFVersion) { public XMPSchemaPDFAExtensions(IZUGFeRDExporter ze, XMPMetadata metadata, int ZFVersion) {
super(metadata); super(metadata);
exporter=ze; exporter=ze;
setZUGFeRDVersion(ZFVersion); setZUGFeRDVersion(ZFVersion);
attachExtensions(metadata, true); attachExtensions(metadata, true);
} }
public XMPSchemaPDFAExtensions(ZUGFeRDExporter ze, XMPMetadata metadata, int ZFVersion, boolean withZF) { public XMPSchemaPDFAExtensions(IZUGFeRDExporter ze, XMPMetadata metadata, int ZFVersion, boolean withZF) {
super(metadata); super(metadata);
exporter=ze; exporter=ze;
setZUGFeRDVersion(ZFVersion); setZUGFeRDVersion(ZFVersion);

View File

@@ -41,17 +41,12 @@ public class XMPSchemaZugferd extends XMPSchema {
* @param prefix the xml namespace prefix for the XMP, zf for ZUGFeRD, fx for Factur-X * @param prefix the xml namespace prefix for the XMP, zf for ZUGFeRD, fx for Factur-X
* @param filename the filename of the invoice * @param filename the filename of the invoice
*/ */
public XMPSchemaZugferd(XMPMetadata metadata, int zfVersion, boolean isFacturX, ZUGFeRDConformanceLevel conformanceLevel, String URN, String prefix, String filename) { public XMPSchemaZugferd(XMPMetadata metadata, int zfVersion, boolean isFacturX, Profile conformanceLevel, String URN, String prefix, String filename) {
super(metadata, URN, prefix, "ZUGFeRD Schema"); super(metadata, URN, prefix, "ZUGFeRD Schema");
setAboutAsSimple(""); setAboutAsSimple("");
String conformanceLevelValue = conformanceLevel.name(); String conformanceLevelValue = conformanceLevel.getXMPName();
if (conformanceLevelValue.equals("BASICWL")) {
conformanceLevelValue = "BASIC WL";
} else if (conformanceLevelValue.equals("EN16931")) {
conformanceLevelValue = "EN 16931";
}
setTextPropertyValue("ConformanceLevel", conformanceLevelValue); setTextPropertyValue("ConformanceLevel", conformanceLevelValue);
setTextPropertyValue("DocumentType", "INVOICE"); setTextPropertyValue("DocumentType", "INVOICE");
setTextPropertyValue("DocumentFileName", filename); setTextPropertyValue("DocumentFileName", filename);

View File

@@ -0,0 +1,75 @@
/**
* *********************************************************************
* <p>
* Copyright 2018 Jochen Staerk
* <p>
* Use is subject to license terms.
* <p>
* 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.
* <p>
* 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.
* <p>
* See the License for the specific language governing permissions and
* limitations under the License.
* <p>
* **********************************************************************
*/
package org.mustangproject.ZUGFeRD;
import org.apache.pdfbox.cos.*;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
import org.apache.pdfbox.preflight.PreflightDocument;
import org.apache.pdfbox.preflight.exception.ValidationException;
import org.apache.pdfbox.preflight.parser.PreflightParser;
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.AdobePDFSchema;
import org.apache.xmpbox.schema.DublinCoreSchema;
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
import org.apache.xmpbox.schema.XMPBasicSchema;
import org.apache.xmpbox.type.BadFieldValueException;
import org.apache.xmpbox.xml.XmpSerializer;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.xml.transform.TransformerException;
import java.io.*;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
public class XRExporter implements IExporter {
IXMLProvider xmlProvider;
IExportableTransaction trans;
public XRExporter() {
}
@Override
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
this.trans=trans;
return this;
}
@Override
public void export(String ZUGFeRDfilename) throws IOException {
export(new FileOutputStream(new File(ZUGFeRDfilename)));
}
@Override
public void export(OutputStream output) throws IOException {
xmlProvider.generateXML(trans);
byte[] bytes=xmlProvider.getXML();
output.write(bytes, 0, bytes.length);
}
}

View File

@@ -24,33 +24,27 @@ import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat; import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter; import org.dom4j.io.XMLWriter;
import org.mustangproject.XMLTools; import org.mustangproject.XMLTools;
import org.mustangproject.ZUGFeRD.*;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider { public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLProvider {
//// MAIN CLASS //// MAIN CLASS
protected byte[] zugferdData; protected byte[] zugferdData;
private IZUGFeRDExportableTransaction trans;
private ZUGFeRDConformanceLevel level;
private String paymentTermsDescription; private String paymentTermsDescription;
SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd");
protected Profile profile=Profiles.getByName("COMFORT",1);
@Override
public void setProfile(ZUGFeRDConformanceLevel level) {
this.level = level;
}
/** /**
* enables the flag to indicate a test invoice in the XML structure * enables the flag to indicate a test invoice in the XML structure
@@ -74,6 +68,12 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
return XMLTools.nDigitFormat(value, 4); return XMLTools.nDigitFormat(value, 4);
} }
@Override
public Profile getProfile() {
return profile;
}
@Override @Override
public byte[] getXML() { public byte[] getXML() {
@@ -100,101 +100,14 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
} }
private BigDecimal getTotalPrepaid() {
if (trans.getTotalPrepaidAmount() == null) {
return new BigDecimal(0);
} else {
return trans.getTotalPrepaidAmount();
}
}
private BigDecimal getTotalGross() {
BigDecimal res = getTotal();
HashMap<BigDecimal, VATAmount> VATPercentAmountMap = getVATPercentAmountMap();
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
res = res.add(amount.getCalculated());
}
return res;
}
private BigDecimal getTotal() {
BigDecimal res = new BigDecimal(0);
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
LineCalc lc = new LineCalc(currentItem);
res = res.add(lc.getItemTotalNetAmount());
}
return res;
}
/**
* which taxes have been used with which amounts in this transaction, empty for
* no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable to 19% VAT
* (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT) 190 Eur
*
* @return which taxes have been used with which amounts in this invoice
*/
private HashMap<BigDecimal, VATAmount> getVATPercentAmountMap() {
HashMap<BigDecimal, VATAmount> hm = new HashMap<>();
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
BigDecimal percent = currentItem.getProduct().getVATPercent();
LineCalc lc = new LineCalc(currentItem);
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(),
trans.getDocumentCode());
VATAmount current = hm.get(percent);
if (current == null) {
hm.put(percent, itemVATAmount);
} else {
hm.put(percent, current.add(itemVATAmount));
}
}
return hm;
}
@Override @Override
public String getProfile() { public void generateXML(IExportableTransaction trans) {
return "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort";
}
protected String getContactAsXML(IZUGFeRDExportableContact contact) {
String xml = " <ram:Name>" + XMLTools.encodeXML(contact.getName()) + "</ram:Name>\n" //$NON-NLS-2$
// + " <DefinedTradeContact>\n"
// + " <PersonName>xxx</PersonName>\n"
// + " </DefinedTradeContact>\n"
+ " <ram:PostalTradeAddress>\n"
+ " <ram:PostcodeCode>" + XMLTools.encodeXML(contact.getZIP())
+ "</ram:PostcodeCode>\n"
+ " <ram:LineOne>" + XMLTools.encodeXML(contact.getStreet())
+ "</ram:LineOne>\n";
if (trans.getRecipient().getAdditionalAddress() != null) {
xml += " <ram:LineTwo>" + XMLTools.encodeXML(contact.getAdditionalAddress())
+ "</ram:LineTwo>\n";
}
xml += " <ram:CityName>" + XMLTools.encodeXML(contact.getLocation())
+ "</ram:CityName>\n"
+ " <ram:CountryID>" + XMLTools.encodeXML(contact.getCountry())
+ "</ram:CountryID>\n"
+ " </ram:PostalTradeAddress>\n";
if (contact.getVATID() != null) {
xml += " <ram:SpecifiedTaxRegistration>\n"
+ " <ram:ID schemeID=\"VA\">" + XMLTools.encodeXML(contact.getVATID())
+ "</ram:ID>\n"
+ " </ram:SpecifiedTaxRegistration>\n";
}
return xml;
}
@Override
public void generateXML(IZUGFeRDExportableTransaction trans) {
this.trans = trans; this.trans = trans;
boolean hasDueDate=false; boolean hasDueDate=false;
String taxCategoryCode=""; String taxCategoryCode="";
SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd");
String exemptionReason=""; String exemptionReason="";
if (trans.getPaymentTermDescription()!=null) { if (trans.getPaymentTermDescription()!=null) {
@@ -227,8 +140,11 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
+ XMLTools.encodeXML(trans.getSubjectNote())+ "</ram:Content>\n" + XMLTools.encodeXML(trans.getSubjectNote())+ "</ram:Content>\n"
+ "</ram:IncludedNote>\n"; + "</ram:IncludedNote>\n";
} }
String typecode="380";
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" if (trans.getDocumentCode()!=null) {
typecode=trans.getDocumentCode();
}
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<rsm:CrossIndustryDocument xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:rsm=\"urn:ferd:CrossIndustryDocument:invoice:1p0\"" + "<rsm:CrossIndustryDocument xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:rsm=\"urn:ferd:CrossIndustryDocument:invoice:1p0\""
// + " // + "
@@ -241,13 +157,13 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
// <ram:TestIndicator><udt:Indicator>"+testBooleanStr+"</udt:Indicator></ram:TestIndicator>\n" // <ram:TestIndicator><udt:Indicator>"+testBooleanStr+"</udt:Indicator></ram:TestIndicator>\n"
// //
+ " <ram:GuidelineSpecifiedDocumentContextParameter>\n" + " <ram:GuidelineSpecifiedDocumentContextParameter>\n"
+ " <ram:ID>" + getProfile() + "</ram:ID>\n" + " <ram:ID>" + getProfile().getID() + "</ram:ID>\n"
+ " </ram:GuidelineSpecifiedDocumentContextParameter>\n" + " </ram:GuidelineSpecifiedDocumentContextParameter>\n"
+ " </rsm:SpecifiedExchangedDocumentContext>\n" + " </rsm:SpecifiedExchangedDocumentContext>\n"
+ " <rsm:HeaderExchangedDocument>\n" + " <rsm:HeaderExchangedDocument>\n"
+ " <ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>\n" //$NON-NLS-2$ + " <ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>\n" //$NON-NLS-2$
+ " <ram:Name>RECHNUNG</ram:Name>\n" + " <ram:Name>RECHNUNG</ram:Name>\n"
+ " <ram:TypeCode>380</ram:TypeCode>\n" + " <ram:TypeCode>"+typecode+"</ram:TypeCode>\n"
+ " <ram:IssueDateTime><udt:DateTimeString format=\"102\">" + " <ram:IssueDateTime><udt:DateTimeString format=\"102\">"
+ zugferdDateFormat.format(trans.getIssueDate()) + "</udt:DateTimeString></ram:IssueDateTime>\n" // date + zugferdDateFormat.format(trans.getIssueDate()) + "</udt:DateTimeString></ram:IssueDateTime>\n" // date
// format // format
@@ -269,25 +185,25 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
xml = xml + " <ram:ID>" + XMLTools.encodeXML(trans.getOwnForeignOrganisationID()) + "</ram:ID>\n"; xml = xml + " <ram:ID>" + XMLTools.encodeXML(trans.getOwnForeignOrganisationID()) + "</ram:ID>\n";
} }
if ((trans.getOwnContact()!=null)&&(trans.getOwnContact().getGlobalID()!=null)&&(trans.getOwnContact().getGlobalIDScheme()!=null)) { if ((trans.getSender()!=null)&&(trans.getSender().getGlobalID()!=null)&&(trans.getSender().getGlobalIDScheme()!=null)) {
xml = xml + " <ram:GlobalID schemeID=\"" + XMLTools.encodeXML(trans.getOwnContact().getGlobalIDScheme()) + "\">" xml = xml + " <ram:GlobalID schemeID=\"" + XMLTools.encodeXML(trans.getSender().getGlobalIDScheme()) + "\">"
+ XMLTools.encodeXML(trans.getOwnContact().getGlobalID()) + "</ram:GlobalID>\n"; + XMLTools.encodeXML(trans.getSender().getGlobalID()) + "</ram:GlobalID>\n";
} }
xml = xml + " <ram:Name>" + XMLTools.encodeXML(trans.getOwnOrganisationName()) + "</ram:Name>\n"; //$NON-NLS-2$ xml = xml + " <ram:Name>" + XMLTools.encodeXML(trans.getOwnOrganisationName()) + "</ram:Name>\n"; //$NON-NLS-2$
if (trans.getOwnContact() != null) { if (trans.getSender().getContact() != null) {
xml = xml + "<ram:DefinedTradeContact>\n" + " <ram:PersonName>" + XMLTools.encodeXML(trans.getOwnContact().getName()) xml = xml + "<ram:DefinedTradeContact>\n" + " <ram:PersonName>" + XMLTools.encodeXML(trans.getSender().getContact().getName())
+ "</ram:PersonName>\n"; + "</ram:PersonName>\n";
if (trans.getOwnContact().getPhone() != null) { if (trans.getSender().getContact().getPhone() != null) {
xml = xml + " <ram:TelephoneUniversalCommunication>\n" + " <ram:CompleteNumber>" xml = xml + " <ram:TelephoneUniversalCommunication>\n" + " <ram:CompleteNumber>"
+ XMLTools.encodeXML(trans.getOwnContact().getPhone()) + "</ram:CompleteNumber>\n" + XMLTools.encodeXML(trans.getSender().getContact().getPhone()) + "</ram:CompleteNumber>\n"
+ " </ram:TelephoneUniversalCommunication>\n"; + " </ram:TelephoneUniversalCommunication>\n";
} }
if (trans.getOwnContact().getEMail() != null) { if (trans.getSender().getContact().getEMail() != null) {
xml = xml + " <ram:EmailURIUniversalCommunication>\n" + " <ram:URIID>" xml = xml + " <ram:EmailURIUniversalCommunication>\n" + " <ram:URIID>"
+ XMLTools.encodeXML(trans.getOwnContact().getEMail()) + "</ram:URIID>\n" + XMLTools.encodeXML(trans.getSender().getContact().getEMail()) + "</ram:URIID>\n"
+ " </ram:EmailURIUniversalCommunication>\n"; + " </ram:EmailURIUniversalCommunication>\n";
} }
xml = xml + " </ram:DefinedTradeContact>"; xml = xml + " </ram:DefinedTradeContact>";
@@ -309,7 +225,7 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
// + " <ID>GE2020211</ID>\n" // + " <ID>GE2020211</ID>\n"
// + " <GlobalID schemeID=\"0088\">4000001987658</GlobalID>\n" // + " <GlobalID schemeID=\"0088\">4000001987658</GlobalID>\n"
xml+=getContactAsXML(trans.getRecipient()); xml+= getTradePartyAsXML(trans.getRecipient());
if ((trans.getOwnVATID()!=null)&&(trans.getOwnOrganisationName()!=null)) { if ((trans.getOwnVATID()!=null)&&(trans.getOwnOrganisationName()!=null)) {
xml = xml + " <ram:SpecifiedTaxRegistration>\n" + " <ram:ID schemeID=\"VA\">" xml = xml + " <ram:SpecifiedTaxRegistration>\n" + " <ram:ID schemeID=\"VA\">"
+ XMLTools.encodeXML(trans.getOwnVATID()) + "</ram:ID>\n" + XMLTools.encodeXML(trans.getOwnVATID()) + "</ram:ID>\n"
@@ -328,19 +244,14 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
+ " <ram:ApplicableSupplyChainTradeDelivery>\n" ; + " <ram:ApplicableSupplyChainTradeDelivery>\n" ;
if (this.trans.getDeliveryAddress()!=null) { if (this.trans.getDeliveryAddress()!=null) {
xml += "<ram:ShipToTradeParty>"+ xml += "<ram:ShipToTradeParty>"+
getContactAsXML(this.trans.getDeliveryAddress())+ getTradePartyAsXML(this.trans.getDeliveryAddress())+
"</ram:ShipToTradeParty>"; "</ram:ShipToTradeParty>";
} }
xml+= " <ram:ActualDeliverySupplyChainEvent>\n" xml+= " <ram:ActualDeliverySupplyChainEvent>\n"
+ " <ram:OccurrenceDateTime>"; + " <ram:OccurrenceDateTime>";
if (trans.getZFDeliveryDate() != null) { if (trans.getDeliveryDate() != null) {
ZUGFeRDDateFormat dateFormat = trans.getZFDeliveryDate().getFormat();
Date date = trans.getZFDeliveryDate().getDate();
xml += "<udt:DateTimeString format=\"" + dateFormat.getDateTimeType() + "\">"
+ dateFormat.getFormatter().format(date) + "</udt:DateTimeString>";
} else if (trans.getDeliveryDate() != null) {
xml += "<udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(trans.getDeliveryDate()) xml += "<udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(trans.getDeliveryDate())
+ "</udt:DateTimeString>"; + "</udt:DateTimeString>";
} else { } else {
@@ -545,12 +456,17 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
} // $NON-NLS-1$ } // $NON-NLS-1$
} }
@Override
public void setProfile(Profile p) {
profile=p;
}
private String buildPaymentTermsXml() { private String buildPaymentTermsXml() {
String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>"; String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>";
IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms(); IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms(); IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
IZUGFeRDDate dueDate = paymentTerms.getDueDate(); Date dueDate = paymentTerms.getDueDate();
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) { if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) {
throw new IllegalStateException( throw new IllegalStateException(
"if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified"); "if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
@@ -558,8 +474,8 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>"; paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>";
if (dueDate != null) { if (dueDate != null) {
paymentTermsXml += "<ram:DueDateDateTime>"; paymentTermsXml += "<ram:DueDateDateTime>";
paymentTermsXml += "<udt:DateTimeString format=\"" + dueDate.getFormat().getDateTimeType() + "\">" paymentTermsXml += "<udt:DateTimeString format=\"102\">"
+ dueDate.getFormat().getFormatter().format(dueDate.getDate()) + "</udt:DateTimeString>"; + zugferdDateFormat.format(dueDate.getDate()) + "</udt:DateTimeString>";
paymentTermsXml += "</ram:DueDateDateTime>"; paymentTermsXml += "</ram:DueDateDateTime>";
} }
@@ -572,10 +488,9 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
+ "</ram:CalculationPercent>"; + "</ram:CalculationPercent>";
if (discountTerms.getBaseDate() != null) { if (discountTerms.getBaseDate() != null) {
Date baseDate = discountTerms.getBaseDate().getDate(); Date baseDate = discountTerms.getBaseDate();
ZUGFeRDDateFormat baseDateFormat = discountTerms.getBaseDate().getFormat();
paymentTermsXml += "<ram:BasisDateTime>"; paymentTermsXml += "<ram:BasisDateTime>";
paymentTermsXml += "<udt:DateTimeString format=\"" + baseDateFormat.getDateTimeType() + "\">" + baseDateFormat.getFormatter().format(baseDate) + "</udt:DateTimeString>"; paymentTermsXml += "<udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(baseDate) + "</udt:DateTimeString>";
paymentTermsXml += "</ram:BasisDateTime>"; paymentTermsXml += "</ram:BasisDateTime>";
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">" paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"

View File

@@ -1,28 +1,29 @@
/** ********************************************************************** /**
* * *********************************************************************
* <p>
* Copyright 2018 Jochen Staerk * Copyright 2018 Jochen Staerk
* * <p>
* Use is subject to license terms. * Use is subject to license terms.
* * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * 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. * of the License at http://www.apache.org/licenses/LICENSE-2.0.
* * <p>
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * <p>
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* * <p>
*********************************************************************** */ * **********************************************************************
*/
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@@ -34,21 +35,18 @@ import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper; import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat; import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter; import org.dom4j.io.XMLWriter;
import org.mustangproject.Invoice;
import org.mustangproject.XMLTools; import org.mustangproject.XMLTools;
public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvider {
//// MAIN CLASS //// MAIN CLASS
protected SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd");
protected byte[] zugferdData; protected byte[] zugferdData;
private IZUGFeRDExportableTransaction trans; protected IExportableTransaction trans;
private ZUGFeRDConformanceLevel level;
private String paymentTermsDescription; private String paymentTermsDescription;
protected Profile profile = Profiles.getByName("EN16931");
@Override
public void setProfile(ZUGFeRDConformanceLevel level) {
this.level = level;
}
/** /**
* enables the flag to indicate a test invoice in the XML structure * enables the flag to indicate a test invoice in the XML structure
@@ -99,7 +97,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
} }
private BigDecimal getTotalPrepaid() { //move
protected BigDecimal getTotalPrepaid() {
if (trans.getTotalPrepaidAmount() == null) { if (trans.getTotalPrepaidAmount() == null) {
return new BigDecimal(0); return new BigDecimal(0);
} else { } else {
@@ -107,9 +106,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
} }
} }
private BigDecimal getTotalGross() { protected BigDecimal getTotalGross() {
BigDecimal res = getTotal(); BigDecimal res = getTaxBasis();
HashMap<BigDecimal, VATAmount> VATPercentAmountMap = getVATPercentAmountMap(); HashMap<BigDecimal, VATAmount> VATPercentAmountMap = getVATPercentAmountMap();
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
@@ -118,23 +117,50 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
return res; return res;
} }
private BigDecimal getTotal() { protected BigDecimal getCharges() {
BigDecimal res = new BigDecimal(0);
IZUGFeRDAllowanceCharge[] charges = trans.getZFCharges();
if ((charges != null) && (charges.length > 0)) {
for (IZUGFeRDAllowanceCharge currentCharge : charges) {
res = res.add(currentCharge.getTotalAmount(this));
}
}
return res;
}
protected BigDecimal getAllowances() {
BigDecimal res = new BigDecimal(0);
IZUGFeRDAllowanceCharge[] allowances = trans.getZFAllowances();
if ((allowances != null) && (allowances.length > 0)) {
for (IZUGFeRDAllowanceCharge currentAllowance : allowances) {
res = res.add(currentAllowance.getTotalAmount(this));
}
}
return res;
}
protected BigDecimal getTotal() {
BigDecimal res = new BigDecimal(0); BigDecimal res = new BigDecimal(0);
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
LineCalc lc = new LineCalc(currentItem); LineCalc lc = new LineCalc(currentItem);
res = res.add(lc.getItemTotalNetAmount()); res = res.add(lc.getItemTotalGrossAmount());
} }
return res; return res;
} }
protected BigDecimal getTaxBasis() {
BigDecimal res = getTotal().add(getCharges()).subtract(getAllowances());
return res;
}
/** /**
* which taxes have been used with which amounts in this transaction, empty for * 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 * no taxes, or e.g. 19:190 and 7:14 if 1000 Eur were applicable to 19% VAT
* (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT) 190 Eur * (=190 EUR VAT) and 200 EUR were applicable to 7% (=14 EUR VAT) 190 Eur
* *
* @return which taxes have been used with which amounts in this invoice * @return which taxes have been used with which amounts in this invoice
*/ */
private HashMap<BigDecimal, VATAmount> getVATPercentAmountMap() { protected HashMap<BigDecimal, VATAmount> getVATPercentAmountMap() {
HashMap<BigDecimal, VATAmount> hm = new HashMap<>(); HashMap<BigDecimal, VATAmount> hm = new HashMap<>();
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
@@ -149,52 +175,138 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
hm.put(percent, current.add(itemVATAmount)); hm.put(percent, current.add(itemVATAmount));
} }
} }
IZUGFeRDAllowanceCharge[] charges = trans.getZFCharges();
if ((charges != null) && (charges.length > 0)) {
for (IZUGFeRDAllowanceCharge currentCharge : charges) {
VATAmount theAmount = hm.get(currentCharge.getTaxPercent());
if (theAmount == null) {
theAmount = new VATAmount(new BigDecimal(0), new BigDecimal(0), "S");
}
theAmount.setBasis(theAmount.getBasis().add(currentCharge.getTotalAmount(this)));
BigDecimal factor = currentCharge.getTaxPercent().divide(new BigDecimal(100));
theAmount.setCalculated(theAmount.getBasis().multiply(factor));
hm.put(currentCharge.getTaxPercent(), theAmount);
}
}
IZUGFeRDAllowanceCharge[] allowances = trans.getZFAllowances();
if ((allowances != null) && (allowances.length > 0)) {
for (IZUGFeRDAllowanceCharge currentAllowance : allowances) {
VATAmount theAmount = hm.get(currentAllowance.getTaxPercent());
if (theAmount == null) {
theAmount = new VATAmount(new BigDecimal(0), new BigDecimal(0), "S");
}
theAmount.setBasis(theAmount.getBasis().subtract(currentAllowance.getTotalAmount(this)));
BigDecimal factor = currentAllowance.getTaxPercent().divide(new BigDecimal(100));
theAmount.setCalculated(theAmount.getBasis().multiply(factor));
hm.put(currentAllowance.getTaxPercent(), theAmount);
}
}
return hm; return hm;
} }
@Override @Override
public String getProfile() { public Profile getProfile() {
// return "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_1.2"; return profile;
return "urn:cen.eu:en16931:2017";
} }
protected String getContactAsXML(IZUGFeRDExportableContact contact) { protected String getTradePartyAsXML(IZUGFeRDExportableTradeParty party) {
String xml = " <ram:Name>" + XMLTools.encodeXML(contact.getName()) + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$ String xml = "";
// + " <DefinedTradeContact>\n" // According EN16931 either GlobalID or seller assigned ID might be present for BuyerTradeParty
// + " <PersonName>xxx</PersonName>\n" // and ShipToTradeParty, but not both. Prefer seller assigned ID for now.
// + " </DefinedTradeContact>\n" if (party.getID() != null) {
+ " <ram:PostalTradeAddress>\n" //$NON-NLS-1$ xml += " <ram:ID>" + XMLTools.encodeXML(party.getID()) + "</ram:ID>\n";
+ " <ram:PostcodeCode>" + XMLTools.encodeXML(contact.getZIP()) //$NON-NLS-1$ } else if ((party.getGlobalIDScheme() != null) && (party.getGlobalID() != null)) {
+ "</ram:PostcodeCode>\n" //$NON-NLS-1$ xml = xml + " <ram:GlobalID schemeID=\"" + XMLTools.encodeXML(party.getGlobalIDScheme()) + "\">"
+ " <ram:LineOne>" + XMLTools.encodeXML(contact.getStreet()) //$NON-NLS-1$ + XMLTools.encodeXML(party.getGlobalID()) + "</ram:GlobalID>\n";
+ "</ram:LineOne>\n"; //$NON-NLS-1$
if (trans.getRecipient().getAdditionalAddress() != null) {
xml += " <ram:LineTwo>" + XMLTools.encodeXML(contact.getAdditionalAddress()) //$NON-NLS-1$
+ "</ram:LineTwo>\n"; //$NON-NLS-1$
} }
xml += " <ram:CityName>" + XMLTools.encodeXML(contact.getLocation()) //$NON-NLS-1$ xml += " <ram:Name>" + XMLTools.encodeXML(party.getName()) + "</ram:Name>\n"; //$NON-NLS-2$
+ "</ram:CityName>\n" //$NON-NLS-1$
+ " <ram:CountryID>" + XMLTools.encodeXML(contact.getCountry()) //$NON-NLS-1$ if (party.getContact() != null) {
+ "</ram:CountryID>\n" //$NON-NLS-1$ xml = xml + "<ram:DefinedTradeContact>\n" + " <ram:PersonName>" + XMLTools.encodeXML(party.getContact().getName())
+ " </ram:PostalTradeAddress>\n"; //$NON-NLS-1$ + "</ram:PersonName>\n";
if (contact.getVATID() != null) { if (party.getContact().getPhone() != null) {
xml += " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:ID schemeID=\"VA\">" + XMLTools.encodeXML(contact.getVATID()) //$NON-NLS-1$ xml = xml + " <ram:TelephoneUniversalCommunication>\n" + " <ram:CompleteNumber>"
+ "</ram:ID>\n" //$NON-NLS-1$ + XMLTools.encodeXML(party.getContact().getPhone()) + "</ram:CompleteNumber>\n"
+ " </ram:SpecifiedTaxRegistration>\n"; //$NON-NLS-1$ + " </ram:TelephoneUniversalCommunication>\n";
}
if (party.getContact().getFax() != null) {
xml = xml + " <ram:FaxUniversalCommunication>\n" + " <ram:CompleteNumber>"
+ XMLTools.encodeXML(party.getContact().getFax()) + "</ram:CompleteNumber>\n"
+ " </ram:FaxUniversalCommunication>\n";
}
if (party.getContact().getEMail() != null) {
xml = xml + " <ram:EmailURIUniversalCommunication>\n" + " <ram:URIID>"
+ XMLTools.encodeXML(party.getContact().getEMail()) + "</ram:URIID>\n"
+ " </ram:EmailURIUniversalCommunication>\n";
}
xml = xml + " </ram:DefinedTradeContact>";
}
xml += " <ram:PostalTradeAddress>\n"
+ " <ram:PostcodeCode>" + XMLTools.encodeXML(party.getZIP())
+ "</ram:PostcodeCode>\n"
+ " <ram:LineOne>" + XMLTools.encodeXML(party.getStreet())
+ "</ram:LineOne>\n";
if (party.getAdditionalAddress() != null) {
xml += " <ram:LineTwo>" + XMLTools.encodeXML(party.getAdditionalAddress())
+ "</ram:LineTwo>\n";
}
xml += " <ram:CityName>" + XMLTools.encodeXML(party.getLocation())
+ "</ram:CityName>\n"
+ " <ram:CountryID>" + XMLTools.encodeXML(party.getCountry())
+ "</ram:CountryID>\n"
+ " </ram:PostalTradeAddress>\n";
if (party.getVATID() != null) {
xml += " <ram:SpecifiedTaxRegistration>\n"
+ " <ram:ID schemeID=\"VA\">" + XMLTools.encodeXML(party.getVATID())
+ "</ram:ID>\n"
+ " </ram:SpecifiedTaxRegistration>\n";
}
if (party.getTaxID() != null) {
xml += " <ram:SpecifiedTaxRegistration>\n"
+ " <ram:ID schemeID=\"FC\">" + XMLTools.encodeXML(party.getTaxID())
+ "</ram:ID>\n"
+ " </ram:SpecifiedTaxRegistration>\n";
} }
return xml; return xml;
} }
protected String getAllowanceChargeStr(IZUGFeRDAllowanceCharge allowance, IAbsoluteValueProvider item) {
String percentage = "";
String chargeIndicator = "false";
if (allowance.getPercent() != null) {
percentage = "<ram:CalculationPercent>" + allowance.getPercent() + "</ram:CalculationPercent>";
percentage += "<ram:BasisAmount>" + item.getValue() + "</ram:BasisAmount>";
}
if (allowance.isCharge()) {
chargeIndicator = "true";
}
String allowanceChargeStr = "<ram:AppliedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" + chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage + "<ram:ActualAmount>" + priceFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount></ram:AppliedTradeAllowanceCharge>";
return allowanceChargeStr;
}
@Override @Override
public void generateXML(IZUGFeRDExportableTransaction trans) { public void generateXML(IExportableTransaction trans) {
this.trans = trans; this.trans = trans;
boolean hasDueDate = false; boolean hasDueDate = false;
String taxCategoryCode = ""; String taxCategoryCode = "";
SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); //$NON-NLS-1$ SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); //$NON-NLS-1$
String exemptionReason = ""; String exemptionReason = "";
if (trans.getPaymentTermDescription() != null) { if (trans.getPaymentTermDescription() != null) {
@@ -228,28 +340,33 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
+ "</ram:IncludedNote>\n"; + "</ram:IncludedNote>\n";
} }
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" //$NON-NLS-1$ String typecode = "380";
if (trans.getDocumentCode() != null) {
typecode = trans.getDocumentCode();
}
String xml = "<?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\"" + "<rsm:CrossIndustryInvoice xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:rsm=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100\""
// + " // + "
// xsi:schemaLocation=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100 // xsi:schemaLocation=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100
// ../Schema/ZUGFeRD1p0.xsd\"" // ../Schema/ZUGFeRD1p0.xsd\""
+ " xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100\"" + " xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100\""
+ " xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100\">\n" //$NON-NLS-1$ + " xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100\">\n"
+ " <rsm:ExchangedDocumentContext>\n" //$NON-NLS-1$ + " <rsm:ExchangedDocumentContext>\n"
// + " // + "
// <ram:TestIndicator><udt:Indicator>"+testBooleanStr+"</udt:Indicator></ram:TestIndicator>\n" // <ram:TestIndicator><udt:Indicator>"+testBooleanStr+"</udt:Indicator></ram:TestIndicator>\n"
// //$NON-NLS-1$ //
+ " <ram:GuidelineSpecifiedDocumentContextParameter>\n" //$NON-NLS-1$ + " <ram:GuidelineSpecifiedDocumentContextParameter>\n"
+ " <ram:ID>" + getProfile() + "</ram:ID>\n" //$NON-NLS-1$ + " <ram:ID>" + getProfile().getID() + "</ram:ID>\n"
+ " </ram:GuidelineSpecifiedDocumentContextParameter>\n" //$NON-NLS-1$ + " </ram:GuidelineSpecifiedDocumentContextParameter>\n"
+ " </rsm:ExchangedDocumentContext>\n" //$NON-NLS-1$ + " </rsm:ExchangedDocumentContext>\n"
+ " <rsm:ExchangedDocument>\n" //$NON-NLS-1$ + " <rsm:ExchangedDocument>\n"
+ " <ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$ + " <ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>\n" //$NON-NLS-2$
// + " <ram:Name>RECHNUNG</ram:Name>\n" //$NON-NLS-1$ // + " <ram:Name>RECHNUNG</ram:Name>\n"
+ " <ram:TypeCode>380</ram:TypeCode>\n" //$NON-NLS-1$ // + " <ram:TypeCode>380</ram:TypeCode>\n"
+ " <ram:IssueDateTime><udt:DateTimeString format=\"102\">" //$NON-NLS-1$ + " <ram:TypeCode>" + typecode + "</ram:TypeCode>\n"
+ zugferdDateFormat.format(trans.getIssueDate()) + "</udt:DateTimeString></ram:IssueDateTime>\n" // date //$NON-NLS-1$ + " <ram:IssueDateTime><udt:DateTimeString format=\"102\">"
+ zugferdDateFormat.format(trans.getIssueDate()) + "</udt:DateTimeString></ram:IssueDateTime>\n" // date
// format // format
// was // was
// 20130605 // 20130605
@@ -257,8 +374,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
+ rebateAgreement + rebateAgreement
+ senderReg + senderReg
+ " </rsm:ExchangedDocument>\n" //$NON-NLS-1$ + " </rsm:ExchangedDocument>\n"
+ " <rsm:SupplyChainTradeTransaction>\n"; //$NON-NLS-1$ + " <rsm:SupplyChainTradeTransaction>\n";
int lineID = 0; int lineID = 0;
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
lineID++; lineID++;
@@ -268,11 +385,11 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
} }
LineCalc lc = new LineCalc(currentItem); LineCalc lc = new LineCalc(currentItem);
xml = xml + " <ram:IncludedSupplyChainTradeLineItem>\n" + //$NON-NLS-1$ xml = xml + " <ram:IncludedSupplyChainTradeLineItem>\n" +
" <ram:AssociatedDocumentLineDocument>\n" //$NON-NLS-1$ " <ram:AssociatedDocumentLineDocument>\n"
+ " <ram:LineID>" + lineID + "</ram:LineID>\n" //$NON-NLS-1$ //$NON-NLS-2$ + " <ram:LineID>" + lineID + "</ram:LineID>\n" //$NON-NLS-2$
+ " </ram:AssociatedDocumentLineDocument>\n" //$NON-NLS-1$ + " </ram:AssociatedDocumentLineDocument>\n"
+ " <ram:SpecifiedTradeProduct>\n"; //$NON-NLS-1$ + " <ram:SpecifiedTradeProduct>\n";
// + " <GlobalID schemeID=\"0160\">4012345001235</GlobalID>\n" // + " <GlobalID schemeID=\"0160\">4012345001235</GlobalID>\n"
if (currentItem.getProduct().getSellerAssignedID() != null) { if (currentItem.getProduct().getSellerAssignedID() != null) {
xml = xml + " <ram:SellerAssignedID>" xml = xml + " <ram:SellerAssignedID>"
@@ -282,142 +399,113 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
xml = xml + " <ram:BuyerAssignedID>" xml = xml + " <ram:BuyerAssignedID>"
+ XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "</ram:BuyerAssignedID>\n"; + XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "</ram:BuyerAssignedID>\n";
} }
xml = xml + " <ram:Name>" + XMLTools.encodeXML(currentItem.getProduct().getName()) + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$ String allowanceChargeStr = "";
+ " <ram:Description>" + XMLTools.encodeXML(currentItem.getProduct().getDescription()) //$NON-NLS-1$ if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
+ "</ram:Description>\n" //$NON-NLS-1$ for (IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
+ " </ram:SpecifiedTradeProduct>\n" //$NON-NLS-1$ allowanceChargeStr += getAllowanceChargeStr(allowance, currentItem);
}
}
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
for (IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
allowanceChargeStr += getAllowanceChargeStr(charge, currentItem);
+ " <ram:SpecifiedLineTradeAgreement>\n" //$NON-NLS-1$ }
+ " <ram:GrossPriceProductTradePrice>\n" //$NON-NLS-1$ }
+ " <ram:ChargeAmount>" + priceFormat(lc.getPriceGross()) //$NON-NLS-1$
+ "</ram:ChargeAmount>\n" //$NON-NLS-1$ //currencyID=\"EUR\"
+ " <ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit()) //$NON-NLS-1$ xml = xml + " <ram:Name>" + XMLTools.encodeXML(currentItem.getProduct().getName()) + "</ram:Name>\n" //$NON-NLS-2$
+ "\">" + quantityFormat(currentItem.getBasisQuantity()) +"</ram:BasisQuantity>\n" //$NON-NLS-1$ + " <ram:Description>" + XMLTools.encodeXML(currentItem.getProduct().getDescription())
+ "</ram:Description>\n"
+ " </ram:SpecifiedTradeProduct>\n"
+ " <ram:SpecifiedLineTradeAgreement>\n"
+ " <ram:GrossPriceProductTradePrice>\n"
+ " <ram:ChargeAmount>" + priceFormat(lc.getPriceGross())
+ "</ram:ChargeAmount>\n" //currencyID=\"EUR\"
+ "<ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit())
+ "\">" + quantityFormat(currentItem.getBasisQuantity()) + "</ram:BasisQuantity>\n"
+ allowanceChargeStr
// + " <AppliedTradeAllowanceCharge>\n" // + " <AppliedTradeAllowanceCharge>\n"
// + " <ChargeIndicator>false</ChargeIndicator>\n" // + " <ChargeIndicator>false</ChargeIndicator>\n"
// + " <ActualAmount currencyID=\"EUR\">0.6667</ActualAmount>\n" // + " <ActualAmount currencyID=\"EUR\">0.6667</ActualAmount>\n"
// + " <Reason>Rabatt</Reason>\n" // + " <Reason>Rabatt</Reason>\n"
// + " </AppliedTradeAllowanceCharge>\n" // + " </AppliedTradeAllowanceCharge>\n"
+ " </ram:GrossPriceProductTradePrice>\n" //$NON-NLS-1$ + " </ram:GrossPriceProductTradePrice>\n"
+ " <ram:NetPriceProductTradePrice>\n" //$NON-NLS-1$ + " <ram:NetPriceProductTradePrice>\n"
+ " <ram:ChargeAmount>" + priceFormat(currentItem.getPrice()) //$NON-NLS-1$ + " <ram:ChargeAmount>" + priceFormat(lc.getPrice())
+ "</ram:ChargeAmount>\n" //$NON-NLS-1$ // currencyID=\"EUR\" + "</ram:ChargeAmount>\n" // currencyID=\"EUR\"
+ " <ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit()) //$NON-NLS-1$ + " <ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit())
+ "\">" + quantityFormat(currentItem.getBasisQuantity()) +"</ram:BasisQuantity>\n" //$NON-NLS-1$ + "\">" + quantityFormat(currentItem.getBasisQuantity()) + "</ram:BasisQuantity>\n"
+ " </ram:NetPriceProductTradePrice>\n" //$NON-NLS-1$ + " </ram:NetPriceProductTradePrice>\n"
+ " </ram:SpecifiedLineTradeAgreement>\n" //$NON-NLS-1$ + " </ram:SpecifiedLineTradeAgreement>\n"
+ " <ram:SpecifiedLineTradeDelivery>\n" //$NON-NLS-1$ + " <ram:SpecifiedLineTradeDelivery>\n"
+ " <ram:BilledQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit()) + "\">" //$NON-NLS-1$ //$NON-NLS-2$ + " <ram:BilledQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit()) + "\">" //$NON-NLS-2$
+ quantityFormat(currentItem.getQuantity()) + "</ram:BilledQuantity>\n" //$NON-NLS-1$ + quantityFormat(currentItem.getQuantity()) + "</ram:BilledQuantity>\n"
+ " </ram:SpecifiedLineTradeDelivery>\n" //$NON-NLS-1$ + " </ram:SpecifiedLineTradeDelivery>\n"
+ " <ram:SpecifiedLineTradeSettlement>\n" //$NON-NLS-1$ + " <ram:SpecifiedLineTradeSettlement>\n"
+ " <ram:ApplicableTradeTax>\n" //$NON-NLS-1$ + " <ram:ApplicableTradeTax>\n"
+ " <ram:TypeCode>VAT</ram:TypeCode>\n" //$NON-NLS-1$ + " <ram:TypeCode>VAT</ram:TypeCode>\n"
+ exemptionReason + exemptionReason
+ " <ram:CategoryCode>"+currentItem.getProduct().getTaxCategoryCode()+"</ram:CategoryCode>\n" //$NON-NLS-1$ + " <ram:CategoryCode>" + currentItem.getProduct().getTaxCategoryCode() + "</ram:CategoryCode>\n"
+ " <ram:RateApplicablePercent>" //$NON-NLS-1$ + " <ram:RateApplicablePercent>"
+ vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>\n" //$NON-NLS-1$ + vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>\n"
+ " </ram:ApplicableTradeTax>\n" //$NON-NLS-1$ + " </ram:ApplicableTradeTax>\n"
+ " <ram:SpecifiedTradeSettlementLineMonetarySummation>\n" //$NON-NLS-1$ + " <ram:SpecifiedTradeSettlementLineMonetarySummation>\n"
+ " <ram:LineTotalAmount>" + currencyFormat(lc.getItemTotalNetAmount()) //$NON-NLS-1$ + " <ram:LineTotalAmount>" + currencyFormat(lc.getItemTotalNetAmount())
+ "</ram:LineTotalAmount>\n" //$NON-NLS-1$ // currencyID=\"EUR\" + "</ram:LineTotalAmount>\n" // currencyID=\"EUR\"
+ " </ram:SpecifiedTradeSettlementLineMonetarySummation>\n"; //$NON-NLS-1$ + " </ram:SpecifiedTradeSettlementLineMonetarySummation>\n";
if (currentItem.getAdditionalReferencedDocumentID() != null) { if (currentItem.getAdditionalReferencedDocumentID() != null) {
xml=xml + " <ram:AdditionalReferencedDocument><ram:IssuerAssignedID>"+currentItem.getAdditionalReferencedDocumentID()+"</ram:IssuerAssignedID><ram:TypeCode>130</ram:TypeCode></ram:AdditionalReferencedDocument>\n"; //$NON-NLS-1$ xml = xml + " <ram:AdditionalReferencedDocument><ram:IssuerAssignedID>" + currentItem.getAdditionalReferencedDocumentID() + "</ram:IssuerAssignedID><ram:TypeCode>130</ram:TypeCode></ram:AdditionalReferencedDocument>\n";
} }
xml=xml + " </ram:SpecifiedLineTradeSettlement>\n" //$NON-NLS-1$ xml = xml + " </ram:SpecifiedLineTradeSettlement>\n"
+ " </ram:IncludedSupplyChainTradeLineItem>\n"; //$NON-NLS-1$ + " </ram:IncludedSupplyChainTradeLineItem>\n";
} }
xml = xml + " <ram:ApplicableHeaderTradeAgreement>\n"; //$NON-NLS-1$ xml = xml + " <ram:ApplicableHeaderTradeAgreement>\n";
if (trans.getReferenceNumber() != null) { if (trans.getReferenceNumber() != null) {
xml = xml + " <ram:BuyerReference>" + XMLTools.encodeXML(trans.getReferenceNumber()) + "</ram:BuyerReference>\n"; xml = xml + " <ram:BuyerReference>" + XMLTools.encodeXML(trans.getReferenceNumber()) + "</ram:BuyerReference>\n";
} }
xml = xml + " <ram:SellerTradeParty>\n"; //$NON-NLS-1$ xml = xml + " <ram:SellerTradeParty>\n"
if (trans.getOwnForeignOrganisationID()!=null) { + getTradePartyAsXML(trans.getSender())
xml = xml + " <ram:ID>" + XMLTools.encodeXML(trans.getOwnForeignOrganisationID()) + "</ram:ID>\n"; + " </ram:SellerTradeParty>\n"
} + " <ram:BuyerTradeParty>\n";
if ((trans.getOwnContact()!=null)&&(trans.getOwnContact().getGlobalID()!=null)&&(trans.getOwnContact().getGlobalIDScheme()!=null)) {
xml = xml + " <ram:GlobalID schemeID=\"" + XMLTools.encodeXML(trans.getOwnContact().getGlobalIDScheme()) + "\">"
+ XMLTools.encodeXML(trans.getOwnContact().getGlobalID()) + "</ram:GlobalID>\n";
}
xml = xml + " <ram:Name>" + XMLTools.encodeXML(trans.getOwnOrganisationName()) + "</ram:Name>\n"; //$NON-NLS-1$ //$NON-NLS-2$
if ((trans.getOwnVATID()!=null)&&(trans.getOwnOrganisationName()!=null)) {
xml = xml + " <ram:SpecifiedLegalOrganization>\n" + " <ram:ID>"
+ XMLTools.encodeXML(trans.getOwnVATID()) + "</ram:ID>\n" + " <ram:TradingBusinessName>"
+ XMLTools.encodeXML(trans.getOwnOrganisationName()) + "</ram:TradingBusinessName>\n"
+ " </ram:SpecifiedLegalOrganization>";
}
if (trans.getOwnContact() != null) {
xml = xml + "<ram:DefinedTradeContact>\n" + " <ram:PersonName>" + XMLTools.encodeXML(trans.getOwnContact().getName())
+ "</ram:PersonName>\n";
if (trans.getOwnContact().getPhone() != null) {
xml = xml + " <ram:TelephoneUniversalCommunication>\n" + " <ram:CompleteNumber>"
+ XMLTools.encodeXML(trans.getOwnContact().getPhone()) + "</ram:CompleteNumber>\n"
+ " </ram:TelephoneUniversalCommunication>\n";
}
if (trans.getOwnContact().getEMail() != null) {
xml = xml + " <ram:EmailURIUniversalCommunication>\n" + " <ram:URIID>"
+ XMLTools.encodeXML(trans.getOwnContact().getEMail()) + "</ram:URIID>\n"
+ " </ram:EmailURIUniversalCommunication>\n";
}
xml = xml + " </ram:DefinedTradeContact>";
}
xml = xml + " <ram:PostalTradeAddress>\n" + " <ram:PostcodeCode>"
+ XMLTools.encodeXML(trans.getOwnZIP()) + "</ram:PostcodeCode>\n" + " <ram:LineOne>"
+ XMLTools.encodeXML(trans.getOwnStreet()) + "</ram:LineOne>\n" + " <ram:CityName>" + XMLTools.encodeXML(trans.getOwnLocation())
+ "</ram:CityName>\n" + " <ram:CountryID>" + XMLTools.encodeXML(trans.getOwnCountry())
+ "</ram:CountryID>\n" + " </ram:PostalTradeAddress>\n"
+ " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:ID schemeID=\"FC\">" + XMLTools.encodeXML(trans.getOwnTaxID()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:ID schemeID=\"VA\">" + XMLTools.encodeXML(trans.getOwnVATID()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " </ram:SellerTradeParty>\n" //$NON-NLS-1$
+ " <ram:BuyerTradeParty>\n"; //$NON-NLS-1$
// + " <ID>GE2020211</ID>\n" // + " <ID>GE2020211</ID>\n"
// + " <GlobalID schemeID=\"0088\">4000001987658</GlobalID>\n" // + " <GlobalID schemeID=\"0088\">4000001987658</GlobalID>\n"
xml+=getContactAsXML(trans.getRecipient()); xml += getTradePartyAsXML(trans.getRecipient());
xml += " </ram:BuyerTradeParty>\n"; //$NON-NLS-1$ xml += " </ram:BuyerTradeParty>\n";
if (trans.getBuyerOrderReferencedDocumentID() != null) { if (trans.getBuyerOrderReferencedDocumentID() != null) {
xml = xml + " <ram:BuyerOrderReferencedDocument>\n" //$NON-NLS-1$ xml = xml + " <ram:BuyerOrderReferencedDocument>\n"
+ " <ram:IssuerAssignedID>" //$NON-NLS-1$ + " <ram:IssuerAssignedID>"
+ XMLTools.encodeXML(trans.getBuyerOrderReferencedDocumentID()) + "</ram:IssuerAssignedID>\n" //$NON-NLS-1$ + XMLTools.encodeXML(trans.getBuyerOrderReferencedDocumentID()) + "</ram:IssuerAssignedID>\n"
+ " </ram:BuyerOrderReferencedDocument>\n"; + " </ram:BuyerOrderReferencedDocument>\n";
} }
xml = xml + " </ram:ApplicableHeaderTradeAgreement>\n" //$NON-NLS-1$ if (trans.getContractReferencedDocument() != null) {
xml = xml + " <ram:ContractReferencedDocument>\n"
+ " <ram:IssuerAssignedID>"
+ XMLTools.encodeXML(trans.getContractReferencedDocument()) + "</ram:IssuerAssignedID>\n"
+ " </ram:ContractReferencedDocument>\n";
}
xml = xml + " </ram:ApplicableHeaderTradeAgreement>\n"
+ " <ram:ApplicableHeaderTradeDelivery>\n"; + " <ram:ApplicableHeaderTradeDelivery>\n";
if (this.trans.getDeliveryAddress() != null) { if (this.trans.getDeliveryAddress() != null) {
xml += "<ram:ShipToTradeParty>" + xml += "<ram:ShipToTradeParty>" +
getContactAsXML(this.trans.getDeliveryAddress())+ getTradePartyAsXML(this.trans.getDeliveryAddress()) +
"</ram:ShipToTradeParty>"; "</ram:ShipToTradeParty>";
} }
xml += " <ram:ActualDeliverySupplyChainEvent>\n" xml += " <ram:ActualDeliverySupplyChainEvent>\n"
+ " <ram:OccurrenceDateTime>"; + " <ram:OccurrenceDateTime>";
if (trans.getZFDeliveryDate() != null) { if (trans.getDeliveryDate() != null) {
ZUGFeRDDateFormat dateFormat = trans.getZFDeliveryDate().getFormat();
Date date = trans.getZFDeliveryDate().getDate();
xml += "<udt:DateTimeString format=\"" + dateFormat.getDateTimeType() + "\">"
+ dateFormat.getFormatter().format(date) + "</udt:DateTimeString>";
} else if (trans.getDeliveryDate() != null) {
xml += "<udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(trans.getDeliveryDate()) xml += "<udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(trans.getDeliveryDate())
+ "</udt:DateTimeString>"; + "</udt:DateTimeString>";
} else { } else {
@@ -432,8 +520,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
* " </DeliveryNoteReferencedDocument>\n" * " </DeliveryNoteReferencedDocument>\n"
*/ */
+ " </ram:ApplicableHeaderTradeDelivery>\n" + " <ram:ApplicableHeaderTradeSettlement>\n" //$NON-NLS-2$ + " </ram:ApplicableHeaderTradeDelivery>\n" + " <ram:ApplicableHeaderTradeSettlement>\n" //$NON-NLS-2$
+ " <ram:PaymentReference>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:PaymentReference>\n" //$NON-NLS-1$ //$NON-NLS-2$ + " <ram:PaymentReference>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:PaymentReference>\n" //$NON-NLS-2$
+ " <ram:InvoiceCurrencyCode>" + trans.getCurrency() + "</ram:InvoiceCurrencyCode>\n"; //$NON-NLS-1$ + " <ram:InvoiceCurrencyCode>" + trans.getCurrency() + "</ram:InvoiceCurrencyCode>\n";
if (trans.getTradeSettlementPayment() != null) { if (trans.getTradeSettlementPayment() != null) {
for (IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) { for (IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) {
@@ -458,21 +546,67 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
if (amount != null) { if (amount != null) {
xml += " <ram:ApplicableTradeTax>\n" //$NON-NLS-1$ xml += " <ram:ApplicableTradeTax>\n"
+ " <ram:CalculatedAmount>" + currencyFormat(amount.getCalculated()) //$NON-NLS-1$ + " <ram:CalculatedAmount>" + currencyFormat(amount.getCalculated())
+ "</ram:CalculatedAmount>\n" //$NON-NLS-1$ //currencyID=\"EUR\" + "</ram:CalculatedAmount>\n" //currencyID=\"EUR\"
+ " <ram:TypeCode>VAT</ram:TypeCode>\n" //$NON-NLS-1$ + " <ram:TypeCode>VAT</ram:TypeCode>\n"
+ exemptionReason + exemptionReason
+ " <ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>\n" // currencyID=\"EUR\" + " <ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>\n" // currencyID=\"EUR\"
+ " <ram:CategoryCode>"+taxCategoryCode+"</ram:CategoryCode>\n" //$NON-NLS-1$ + " <ram:CategoryCode>" + taxCategoryCode + "</ram:CategoryCode>\n"
+ " <ram:RateApplicablePercent>" + vatFormat(currentTaxPercent) //$NON-NLS-1$ + " <ram:RateApplicablePercent>" + vatFormat(currentTaxPercent)
+ "</ram:RateApplicablePercent>\n" + " </ram:ApplicableTradeTax>\n"; //$NON-NLS-2$ + "</ram:RateApplicablePercent>\n" + " </ram:ApplicableTradeTax>\n"; //$NON-NLS-2$
} }
} }
if ((trans.getOccurrencePeriodFrom() != null) || (trans.getOccurrencePeriodTo() != null)) {
xml = xml + "<ram:BillingSpecifiedPeriod>";
if (trans.getOccurrencePeriodFrom() != null) {
xml = xml + "<ram:StartDateTime><udt:DateTimeString format='102'>" + zugferdDateFormat.format(trans.getOccurrencePeriodFrom()) + "</udt:DateTimeString></ram:StartDateTime>";
}
if (trans.getOccurrencePeriodTo() != null) {
xml = xml + "<ram:EndDateTime><udt:DateTimeString format='102'>" + zugferdDateFormat.format(trans.getOccurrencePeriodTo()) + "</udt:DateTimeString></ram:EndDateTime>";
}
xml = xml + "</ram:BillingSpecifiedPeriod>";
}
if ((trans.getZFCharges() != null) && (trans.getZFCharges().length > 0)) {
xml = xml + " <ram:SpecifiedTradeAllowanceCharge>\n" +
" <ram:ChargeIndicator>\n" +
" <udt:Indicator>true</udt:Indicator>\n" +
" </ram:ChargeIndicator>\n" +
" <ram:ActualAmount>" + currencyFormat(getCharges()) + "</ram:ActualAmount>\n" +
" <ram:Reason>Charge</ram:Reason>\n" +
" <ram:CategoryTradeTax>\n" +
" <ram:TypeCode>VAT</ram:TypeCode>\n" +
" <ram:CategoryCode>S</ram:CategoryCode>\n" +
" <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>\n" +
" </ram:CategoryTradeTax>\n" +
" </ram:SpecifiedTradeAllowanceCharge> \n";
}
if ((trans.getZFAllowances() != null) && (trans.getZFAllowances().length > 0)) {
xml = xml + " <ram:SpecifiedTradeAllowanceCharge>\n" +
" <ram:ChargeIndicator>\n" +
" <udt:Indicator>false</udt:Indicator>\n" +
" </ram:ChargeIndicator>\n" +
" <ram:ActualAmount>" + currencyFormat(getAllowances()) + "</ram:ActualAmount>\n" +
" <ram:Reason>Allowance</ram:Reason>\n" +
" <ram:CategoryTradeTax>\n" +
" <ram:TypeCode>VAT</ram:TypeCode>\n" +
" <ram:CategoryCode>S</ram:CategoryCode>\n" +
" <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>\n" +
" </ram:CategoryTradeTax>\n" +
" </ram:SpecifiedTradeAllowanceCharge> \n";
}
if (trans.getPaymentTerms() == null) { if (trans.getPaymentTerms() == null) {
xml = xml + " <ram:SpecifiedTradePaymentTerms>\n" //$NON-NLS-1$ xml = xml + " <ram:SpecifiedTradePaymentTerms>\n"
+ " <ram:Description>" + paymentTermsDescription + "</ram:Description>\n"; + " <ram:Description>" + paymentTermsDescription + "</ram:Description>\n";
if (trans.getTradeSettlement() != null) { if (trans.getTradeSettlement() != null) {
@@ -486,36 +620,37 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
if (hasDueDate && (trans.getDueDate() != null)) { if (hasDueDate && (trans.getDueDate() != null)) {
xml = xml + " <ram:DueDateDateTime><udt:DateTimeString format=\"102\">" // $NON-NLS-2$ xml = xml + " <ram:DueDateDateTime><udt:DateTimeString format=\"102\">" // $NON-NLS-2$
+ zugferdDateFormat.format(trans.getDueDate()) + zugferdDateFormat.format(trans.getDueDate())
+ "</udt:DateTimeString></ram:DueDateDateTime>\n";// 20130704 //$NON-NLS-1$ + "</udt:DateTimeString></ram:DueDateDateTime>\n";// 20130704
} }
xml = xml + " </ram:SpecifiedTradePaymentTerms>\n"; //$NON-NLS-1$ xml = xml + " </ram:SpecifiedTradePaymentTerms>\n";
} else { } else {
xml = xml + buildPaymentTermsXml(); xml = xml + buildPaymentTermsXml();
} }
xml = xml + " <ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n" //$NON-NLS-1$
+ " <ram:LineTotalAmount>" + currencyFormat(getTotal()) + "</ram:LineTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ String allowanceTotalLine = "<ram:AllowanceTotalAmount>" + currencyFormat(getAllowances()) + "</ram:AllowanceTotalAmount>";
// currencyID=\"EUR\"
+ " <ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>\n" //$NON-NLS-1$ currencyID=\"EUR\" String chargesTotalLine = "<ram:ChargeTotalAmount>" + currencyFormat(getCharges()) + "</ram:ChargeTotalAmount>";
+ " <ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>\n" //$NON-NLS-1$ //
// currencyID=\"EUR\" xml = xml + " <ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n"
// + " <ChargeTotalAmount currencyID=\"EUR\">5.80</ChargeTotalAmount>\n" + " <ram:LineTotalAmount>" + currencyFormat(getTotal()) + "</ram:LineTotalAmount>\n" //$NON-NLS-2$
// + " <AllowanceTotalAmount currencyID=\"EUR\">14.73</AllowanceTotalAmount>\n" + chargesTotalLine
+ " <ram:TaxBasisTotalAmount>" + currencyFormat(getTotal()) + "</ram:TaxBasisTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ + allowanceTotalLine
+ " <ram:TaxBasisTotalAmount>" + currencyFormat(getTaxBasis()) + "</ram:TaxBasisTotalAmount>\n" //$NON-NLS-2$
// // // //
// currencyID=\"EUR\" // currencyID=\"EUR\"
+ " <ram:TaxTotalAmount currencyID=\"" + trans.getCurrency() + "\">" //$NON-NLS-1$ + " <ram:TaxTotalAmount currencyID=\"" + trans.getCurrency() + "\">"
+ currencyFormat(getTotalGross().subtract(getTotal())) + "</ram:TaxTotalAmount>\n" //$NON-NLS-1$ + currencyFormat(getTotalGross().subtract(getTaxBasis())) + "</ram:TaxTotalAmount>\n"
+ " <ram:GrandTotalAmount>" + currencyFormat(getTotalGross()) + "</ram:GrandTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ + " <ram:GrandTotalAmount>" + currencyFormat(getTotalGross()) + "</ram:GrandTotalAmount>\n" //$NON-NLS-2$
// // // //
// currencyID=\"EUR\" // currencyID=\"EUR\"
+ " <ram:TotalPrepaidAmount>" + currencyFormat(getTotalPrepaid()) + "</ram:TotalPrepaidAmount>\n" + " <ram:TotalPrepaidAmount>" + currencyFormat(getTotalPrepaid()) + "</ram:TotalPrepaidAmount>\n"
+ " <ram:DuePayableAmount>" + currencyFormat(getTotalGross().subtract(getTotalPrepaid())) + "</ram:DuePayableAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ + " <ram:DuePayableAmount>" + currencyFormat(getTotalGross().subtract(getTotalPrepaid())) + "</ram:DuePayableAmount>\n" //$NON-NLS-2$
// // // //
// currencyID=\"EUR\" // currencyID=\"EUR\"
+ " </ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n" //$NON-NLS-1$ + " </ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n"
+ " </ram:ApplicableHeaderTradeSettlement>\n"; //$NON-NLS-1$ + " </ram:ApplicableHeaderTradeSettlement>\n";
// + " <IncludedSupplyChainTradeLineItem>\n" // + " <IncludedSupplyChainTradeLineItem>\n"
// + " <AssociatedDocumentLineDocument>\n" // + " <AssociatedDocumentLineDocument>\n"
// + " <IncludedNote>\n" // + " <IncludedNote>\n"
@@ -525,8 +660,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
// + " </AssociatedDocumentLineDocument>\n" // + " </AssociatedDocumentLineDocument>\n"
// + " </IncludedSupplyChainTradeLineItem>\n"; // + " </IncludedSupplyChainTradeLineItem>\n";
xml = xml + " </rsm:SupplyChainTradeTransaction>\n" //$NON-NLS-1$ xml = xml + " </rsm:SupplyChainTradeTransaction>\n"
+ "</rsm:CrossIndustryInvoice>"; //$NON-NLS-1$ + "</rsm:CrossIndustryInvoice>";
byte[] zugferdRaw; byte[] zugferdRaw;
try { try {
@@ -544,12 +679,17 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
} // $NON-NLS-1$ } // $NON-NLS-1$
} }
@Override
public void setProfile(Profile p) {
profile = p;
}
private String buildPaymentTermsXml() { private String buildPaymentTermsXml() {
String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>"; String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>";
IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms(); IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms(); IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
IZUGFeRDDate dueDate = paymentTerms.getDueDate(); Date dueDate = paymentTerms.getDueDate();
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) { if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) {
throw new IllegalStateException( throw new IllegalStateException(
"if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified"); "if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
@@ -557,8 +697,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>"; paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>";
if (dueDate != null) { if (dueDate != null) {
paymentTermsXml += "<ram:DueDateDateTime>"; paymentTermsXml += "<ram:DueDateDateTime>";
paymentTermsXml += "<udt:DateTimeString format=\"" + dueDate.getFormat().getDateTimeType() + "\">" paymentTermsXml += "<udt:DateTimeString format=\"102\">"
+ dueDate.getFormat().getFormatter().format(dueDate.getDate()) + "</udt:DateTimeString>"; + zugferdDateFormat.format(dueDate) + "</udt:DateTimeString>";
paymentTermsXml += "</ram:DueDateDateTime>"; paymentTermsXml += "</ram:DueDateDateTime>";
} }
@@ -571,10 +711,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
+ "</ram:CalculationPercent>"; + "</ram:CalculationPercent>";
if (discountTerms.getBaseDate() != null) { if (discountTerms.getBaseDate() != null) {
Date baseDate = discountTerms.getBaseDate().getDate(); Date baseDate = discountTerms.getBaseDate();
ZUGFeRDDateFormat baseDateFormat = discountTerms.getBaseDate().getFormat();
paymentTermsXml += "<ram:BasisDateTime>"; paymentTermsXml += "<ram:BasisDateTime>";
paymentTermsXml += "<udt:DateTimeString format=\"" + baseDateFormat.getDateTimeType() + "\">" + baseDateFormat.getFormatter().format(baseDate) + "</udt:DateTimeString>"; paymentTermsXml += "<udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(baseDate) + "</udt:DateTimeString>";
paymentTermsXml += "</ram:BasisDateTime>"; paymentTermsXml += "</ram:BasisDateTime>";
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">" paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
@@ -588,4 +727,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
return paymentTermsXml; return paymentTermsXml;
} }
@Override
public BigDecimal getValue() {
return getTotal();
}
} }

View File

@@ -1,23 +0,0 @@
/** **********************************************************************
*
* 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;
public enum ZUGFeRDConformanceLevel {
BASIC, COMFORT, EXTENDED, EN16931/*=Comfort*/, MINIMUM, BASICWL /*basic without lines, less than basic*/, CIUS, XRECHNUNG
}

View File

@@ -0,0 +1,125 @@
/** **********************************************************************
*
* 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 org.apache.pdfbox.preflight.PreflightDocument;
import org.apache.pdfbox.preflight.exception.ValidationException;
import org.apache.pdfbox.preflight.parser.PreflightParser;
import javax.activation.DataSource;
import java.io.IOException;
import java.io.InputStream;
public class ZUGFeRDExporterFromA1 extends ZUGFeRDExporterFromA3 implements IZUGFeRDExporter {
protected boolean ignorePDFAErrors = false;
public ZUGFeRDExporterFromA1 ignorePDFAErrors() {
this.ignorePDFAErrors = true;
return this;
}
private static boolean isValidA1(DataSource dataSource) throws IOException {
return getPDFAParserValidationResult(new PreflightParser(dataSource));
}
private static boolean getPDFAParserValidationResult(PreflightParser parser) throws IOException {
/*
* Parse the PDF file with PreflightParser that inherits from the
* NonSequentialParser. Some additional controls are present to check a set of
* PDF/A requirements. (Stream length consistency, EOL after some Keyword...)
*/
parser.parse();// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
try (PreflightDocument document = parser.getPreflightDocument()) {
/*
* Once the syntax validation is done, the parser can provide a
* PreflightDocument (that inherits from PDDocument) This document process the
* end of PDF/A validation.
*/
document.validate();
// Get validation result
return document.getResult().isValid();
} catch (ValidationException e) {
/*
* the parse method can throw a SyntaxValidationException if the PDF file can't
* be parsed. In this case, the exception contains an instance of
* ValidationResult
*/
return false;
}
}
public ZUGFeRDExporterFromA1 setProfile(Profile p) {
return (ZUGFeRDExporterFromA1)super.setProfile(p);
}
public ZUGFeRDExporterFromA1 setProfile(String profileName) {
return (ZUGFeRDExporterFromA1)super.setProfile(profileName);
}
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
throw new IOException("File is not a valid PDF/A input file");
}
return true;
}
public ZUGFeRDExporterFromA1() {
ensurePDFisUpgraded = true;
setZUGFeRDVersion(ZUGFeRDExporterFromA3.DefaultZUGFeRDVersion);
}
public ZUGFeRDExporterFromA1 load(String pdfFilename) throws IOException {
return (ZUGFeRDExporterFromA1) super.load(pdfFilename);
}
public ZUGFeRDExporterFromA1 load(byte[] pdfBinary) throws IOException {
return (ZUGFeRDExporterFromA1) super.load(pdfBinary);
}
public ZUGFeRDExporterFromA1 load(InputStream pdfSource) throws IOException{
return (ZUGFeRDExporterFromA1) super.load(pdfSource);
}
public ZUGFeRDExporterFromA1 setCreator(String creator) {
return (ZUGFeRDExporterFromA1) super.setCreator(creator);
}
public ZUGFeRDExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
return (ZUGFeRDExporterFromA1) super.setConformanceLevel(newLevel);
}
public ZUGFeRDExporterFromA1 setProducer(String producer){
return (ZUGFeRDExporterFromA1) super.setProducer(producer);
}
public ZUGFeRDExporterFromA1 setZUGFeRDVersion(int version){
return (ZUGFeRDExporterFromA1) super.setZUGFeRDVersion(version);
}
public ZUGFeRDExporterFromA1 setXML(byte[] zugferdData) throws IOException{
return (ZUGFeRDExporterFromA1) super.setXML(zugferdData);
}
public ZUGFeRDExporterFromA1 disableAutoClose(boolean disableAutoClose){
return (ZUGFeRDExporterFromA1) super.disableAutoClose(disableAutoClose);
}
public ZUGFeRDExporterFromA1 convertOnly() {
setAttachZUGFeRDHeaders(false);
return this;
}
}

View File

@@ -1,43 +1,35 @@
/**
/** ********************************************************************** * *********************************************************************
* * <p>
* Copyright 2018 Jochen Staerk * Copyright 2018 Jochen Staerk
* * <p>
* Use is subject to license terms. * Use is subject to license terms.
* * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * 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. * of the License at http://www.apache.org/licenses/LICENSE-2.0.
* * <p>
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * <p>
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* * <p>
*********************************************************************** */ * **********************************************************************
*/
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
/* import org.apache.pdfbox.cos.*;
* Mustangproject's ZUGFeRD implementation ZUGFeRD exporter Licensed under the import org.apache.pdfbox.io.IOUtils;
* APLv2
*
* @date 2014-07-12
* @version 1.2.0
* @author jstaerk
*
*/
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSObject;
import org.apache.pdfbox.pdmodel.*; import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.common.PDMetadata; import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification; import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile; import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
import org.apache.pdfbox.preflight.PreflightDocument;
import org.apache.pdfbox.preflight.exception.ValidationException;
import org.apache.pdfbox.preflight.parser.PreflightParser;
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.AdobePDFSchema; import org.apache.xmpbox.schema.AdobePDFSchema;
import org.apache.xmpbox.schema.DublinCoreSchema; import org.apache.xmpbox.schema.DublinCoreSchema;
@@ -45,42 +37,32 @@ import org.apache.xmpbox.schema.PDFAIdentificationSchema;
import org.apache.xmpbox.schema.XMPBasicSchema; import org.apache.xmpbox.schema.XMPBasicSchema;
import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.type.BadFieldValueException;
import org.apache.xmpbox.xml.XmpSerializer; import org.apache.xmpbox.xml.XmpSerializer;
import org.mustangproject.FileAttachment;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerException;
import java.io.*; import java.io.*;
import java.util.ArrayList;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class ZUGFeRDExporter implements Closeable { public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporter, IExporter, Closeable {
private boolean isFacturX = true;
public static final int DefaultZUGFeRDVersion = 2; public static final int DefaultZUGFeRDVersion = 2;
private boolean isFacturX = true; protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<FileAttachment>();
/** protected boolean ensurePDFisUpgraded = true;
* To use the ZUGFeRD exporter, implement IZUGFeRDExportableTransaction in
* yourTransaction (which will require you to implement Product, Item and
* Contact) then call doc = PDDocument.load(PDFfilename); // automatically add
* Zugferd to all outgoing invoices ZUGFeRDExporter ze = new ZUGFeRDExporter();
* ze.PDFmakeA3compliant(doc, "Your application name",
* System.getProperty("user.name"), true); ze.PDFattachZugferdFile(doc,
* yourTransaction);
* <p/>
* doc.save(PDFfilename);
*
* @author jstaerk
* @deprecated Use the factory methods {@link #createFromPDFA3(String)},
* {@link #createFromPDFA3(InputStream)} or the
* {@link ZUGFeRDExporterFromA1Factory} instead
*/
// // MAIN CLASS
@Deprecated
private PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
// BASIC, COMFORT etc - may be set from outside.
@Deprecated private boolean disableAutoClose;
private ZUGFeRDConformanceLevel profile = ZUGFeRDConformanceLevel.EN16931; private boolean fileAttached = false;
private Profile profile = null;
private boolean documentPrepared = false;
/** /**
* Data (XML invoice) to be added to the ZUGFeRD PDF. It may be externally set, * Data (XML invoice) to be added to the ZUGFeRD PDF. It may be externally set,
@@ -88,7 +70,6 @@ public class ZUGFeRDExporter implements Closeable {
* default it is null meaning the caller needs to pass a * default it is null meaning the caller needs to pass a
* IZUGFeRDExportableTransaction for the XML to be populated. * IZUGFeRDExportableTransaction for the XML to be populated.
*/ */
IXMLProvider xmlProvider;
protected PDMetadata metadata = null; protected PDMetadata metadata = null;
protected PDFAIdentificationSchema pdfaid = null; protected PDFAIdentificationSchema pdfaid = null;
protected XMPMetadata xmp = null; protected XMPMetadata xmp = null;
@@ -105,39 +86,52 @@ public class ZUGFeRDExporter implements Closeable {
*/ */
protected String creatorTool = "mustangproject"; protected String creatorTool = "mustangproject";
@Deprecated
private boolean ignoreA1Errors;
protected boolean ensurePDFisUpgraded = true;
private PDDocument doc; private PDDocument doc;
int ZFVersion;
private HashMap<String, byte[]> additionalFiles = new HashMap<String, byte[]>(); private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
private boolean disableAutoClose; protected int ZFVersion = DefaultZUGFeRDVersion;
private boolean attachZUGFeRDHeaders = true;
private boolean fileAttached = false;
protected boolean attachZUGFeRDHeaders = true;
private boolean documentPrepared = false;
public ZUGFeRDExporter() {
init();
}
public ZUGFeRDExporter(PDDocument doc2) {
doc = doc2;
init();
}
/** /**
* Adds additional file attachments into the ZF * Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
* @param filename the name of the attachment * metadata level, this will not e.g. convert graphics to JPG-2000)
* @param filecontent the bytearray with the file contents *
* @param pdfFilename filename of an PDF/A1 compliant document
*/ */
public void addAdditionalFile(String filename, byte[] filecontent) { public ZUGFeRDExporterFromA3 load(String pdfFilename) throws IOException {
additionalFiles.put(filename, filecontent);
ensurePDFIsValid(new FileDataSource(pdfFilename));
try (FileInputStream pdf = new FileInputStream(pdfFilename)) {
return load(readAllBytes(pdf));
}
}
public IXMLProvider getProvider() {
return xmlProvider;
}
public ZUGFeRDExporterFromA3 setProfile(Profile p) {
this.profile=p;
if (xmlProvider!=null) {
xmlProvider.setProfile(p);
}
return this;
}
public ZUGFeRDExporterFromA3 setProfile(String profilename) {
this.profile=Profiles.getByName(profilename);
if (xmlProvider!=null) {
xmlProvider.setProfile(this.profile);
}
return this;
}
public ZUGFeRDExporterFromA3 addAdditionalFile(String name, byte[] content) {
fileAttachments.add(new FileAttachment(name, "text/xml", "Supplement", content).setDescription("ZUGFeRD extension/additional data"));
return this;
} }
/*** /***
@@ -174,241 +168,70 @@ public class ZUGFeRDExporter implements Closeable {
/*** /***
* internal helper: return the name of the file attachment for the given zf/fx version * internal helper: return the name of the file attachment for the given zf/fx version
* @param ver the zf/fx version * @param ver the zf/fx version
* @param profile which profile to be used, e.g. Profiles.getByName("EN16931")
* @return the filename of the file to be embedded * @return the filename of the file to be embedded
*/ */
public String getFilenameForVersion(int ver) { public String getFilenameForVersion(int ver, Profile profile) {
if (isFacturX) { if (isFacturX) {
return "factur-x.xml"; return "factur-x.xml";
} else { } else {
if (ver == 1) { if (ver == 1) {
return "ZUGFeRD-invoice.xml"; return "ZUGFeRD-invoice.xml";
} else {
if (profile.getName().equals("XRECHNUNG")) {
return "xrechnung.xml";
} else { } else {
return "zugferd-invoice.xml"; return "zugferd-invoice.xml";
} }
} }
} }
@Deprecated
public void setZUGFeRDVersion(int ver) {
if (ver == 1) {
ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider();
disableFacturX();
this.xmlProvider = z1p;
} else if (ver == 2) {
ZUGFeRD2PullProvider z2p = new ZUGFeRD2PullProvider();
this.xmlProvider = z2p;
} else {
throw new IllegalArgumentException("Version not supported");
}
ZFVersion = ver;
} }
public IXMLProvider getProvider() {
return xmlProvider;
}
private void init() {
setZUGFeRDVersion(DefaultZUGFeRDVersion);
}
/** /**
* Factur-X is now set by default since ZF 2.1, you have to disable it if you dont wont it * Factur-X is now set by default since ZF 2.1, you have to disable it if you dont wont it
* Generate ZF2.1 files with filename factur-x.xml * Generate ZF2.1 files with filename factur-x.xml
*
* @deprecated * @deprecated
* */ * @return this (fluent setter)
public void setFacturX() { */
public ZUGFeRDExporterFromA3 setFacturX() {
isFacturX = true; isFacturX = true;
return this;
} }
/*** /***
* Generate ZF2.0/2.1 files with filename zugferd-invoice.xml instead of factur-x.xml * Generate ZF2.0/2.1 files with filename zugferd-invoice.xml instead of factur-x.xml
*/ */
public void disableFacturX() { public IZUGFeRDExporter disableFacturX() {
isFacturX = false; isFacturX = false;
} return this;
/**
* All files are PDF/A-3, setConformance refers to the level conformance.
*
* PDF/A-3 has three conformance levels, called "A", "U" and "B".
* <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>
* 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
*/
@Deprecated
public void setConformanceLevel(PDFAConformanceLevel newLevel) {
if (newLevel == null) {
throw new NullPointerException("pdf conformance level");
}
conformanceLevel = newLevel;
} }
/**
* 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>
* 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>
* 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
*/
@Deprecated
public void setConformanceLevel(String newLevel) {
conformanceLevel = PDFAConformanceLevel.findByLetter(newLevel);
}
/**
* enables the flag to indicate a test invoice in the XML structure
*/
public void setTest() {
xmlProvider.setTest();
}
/**
* @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead
*/
@Deprecated
public void ignoreA1Errors() {
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
public void loadPDFA3(String filename) throws IOException {
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)));
}
/**
* 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));
}
/** /**
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the * 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) * 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
public PDDocumentCatalog PDFmakeA3compliant(String filename, String producer, String creator,
boolean attachZugferdHeaders) throws IOException, TransformerException {
doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(filename).doc;
return doc.getDocumentCatalog();
}
/***
* *
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the * @param pdfBinary binary of a PDF/A1 compliant document
* 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 public ZUGFeRDExporterFromA3 load(byte[] pdfBinary) throws IOException {
public PDDocumentCatalog PDFmakeA3compliant(InputStream file, String producer, String creator, ensurePDFIsValid(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
boolean attachZugferdHeaders) throws IOException, TransformerException { doc = PDDocument.load(pdfBinary);
return this;
doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(file).doc;
return doc.getDocumentCatalog();
} }
public ZUGFeRDExporterFromA3() {
private IExporterFactory createPDFA1Factory() { super();
ZUGFeRDExporterFromA1Factory factory = new ZUGFeRDExporterFromA1Factory(); ensurePDFisUpgraded = false;
if (ignoreA1Errors) {
factory.ignorePDFAErrors();
}
return factory.setZUGFeRDConformanceLevel(profile).setConformanceLevel(conformanceLevel);
} }
@Override public void attachFile(FileAttachment file) {
public void close() throws IOException { fileAttachments.add(file);
if (doc != null) {
doc.close();
}
}
/**
* Embeds the Zugferd XML structure in a file named ZUGFeRD-invoice.xml.
*
* @param trans a IZUGFeRDExportableTransaction that provides the data-model to
* 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",
"Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)",
"text/xml", xmlProvider.getXML());
for (String filenameAdditional : additionalFiles.keySet()) {
PDFAttachGenericFile(doc, filenameAdditional, "Supplement", "ZUGFeRD extension/additional data", "text/xml", additionalFiles.get(filenameAdditional));
} }
public void attachFile(String filename, byte[] data, String mimetype, String relation) {
FileAttachment fa=new FileAttachment(filename, mimetype, relation, data);
fileAttachments.add(fa);
} }
/*** /***
@@ -422,7 +245,7 @@ public class ZUGFeRDExporter implements Closeable {
} }
if ((!fileAttached) && (attachZUGFeRDHeaders)) { if ((!fileAttached) && (attachZUGFeRDHeaders)) {
throw new IOException( throw new IOException(
"File must be attached (usually with PDFattachZugferdFile) before perfoming this operation"); "File must be attached (usually with setTransaction) before perfoming this operation");
} }
doc.save(ZUGFeRDfilename); doc.save(ZUGFeRDfilename);
if (!disableAutoClose) { if (!disableAutoClose) {
@@ -430,6 +253,13 @@ public class ZUGFeRDExporter implements Closeable {
} }
} }
@Override
public void close() throws IOException {
if (doc != null) {
doc.close();
}
}
/*** /***
* Perform the final export to a now ZUGFeRD-enriched PDF file as OutputStream * Perform the final export to a now ZUGFeRD-enriched PDF file as OutputStream
@@ -442,7 +272,7 @@ public class ZUGFeRDExporter implements Closeable {
} }
if ((!fileAttached) && (attachZUGFeRDHeaders)) { if ((!fileAttached) && (attachZUGFeRDHeaders)) {
throw new IOException( throw new IOException(
"File must be attached (usually with PDFattachZugferdFile) before perfoming this operation"); "File must be attached (usually with setTransaction) before perfoming this operation");
} }
doc.save(output); doc.save(output);
if (!disableAutoClose) { if (!disableAutoClose) {
@@ -513,23 +343,19 @@ public class ZUGFeRDExporter implements Closeable {
// AF entry (Array) in catalog with the FileSpec // AF entry (Array) in catalog with the FileSpec
COSBase AFEntry = (COSBase) doc.getDocumentCatalog().getCOSObject().getItem("AF"); COSBase AFEntry = (COSBase) doc.getDocumentCatalog().getCOSObject().getItem("AF");
if ((AFEntry == null)) if ((AFEntry == null)) {
{
COSArray cosArray = new COSArray(); COSArray cosArray = new COSArray();
cosArray.add(fs); cosArray.add(fs);
doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray); doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray);
} else if (AFEntry instanceof COSArray) } else if (AFEntry instanceof COSArray) {
{
COSArray cosArray = (COSArray) AFEntry; COSArray cosArray = (COSArray) AFEntry;
cosArray.add(fs); cosArray.add(fs);
doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray); doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray);
} else if ((AFEntry instanceof COSObject) && } else if ((AFEntry instanceof COSObject) &&
((COSObject)AFEntry).getObject() instanceof COSArray) ((COSObject) AFEntry).getObject() instanceof COSArray) {
{
COSArray cosArray = (COSArray) ((COSObject) AFEntry).getObject(); COSArray cosArray = (COSArray) ((COSObject) AFEntry).getObject();
cosArray.add(fs); cosArray.add(fs);
} else } else {
{
throw new IOException("Unexpected object type for PDFDocument/Catalog/COSDictionary/Item(AF)"); throw new IOException("Unexpected object type for PDFDocument/Catalog/COSDictionary/Item(AF)");
} }
} }
@@ -542,49 +368,75 @@ public class ZUGFeRDExporter implements Closeable {
* @param zugferdData XML data to be set as a byte array (XML file in raw form). * @param zugferdData XML data to be set as a byte array (XML file in raw form).
* @throws IOException (should not happen) * @throws IOException (should not happen)
*/ */
public void setZUGFeRDXMLData(byte[] zugferdData) throws IOException { public ZUGFeRDExporterFromA3 setXML(byte[] zugferdData) throws IOException {
CustomXMLProvider cus = new CustomXMLProvider(); CustomXMLProvider cus = new CustomXMLProvider();
cus.setXML(zugferdData); cus.setXML(zugferdData);
this.xmlProvider = cus; this.setXMLProvider(cus);
PDFattachZugferdFile(null); prepare();
return this;
} }
/** /**
* Sets the ZUGFeRD profile. * 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 zUGFeRDConformanceLevel the new conformance level * @param pdfSource source to read a PDF/A1 compliant document from
* @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead
*/ */
@Deprecated public ZUGFeRDExporterFromA3 load(InputStream pdfSource) throws IOException {
public void setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zUGFeRDConformanceLevel) { return load(readAllBytes(pdfSource));
if (zUGFeRDConformanceLevel == null) {
throw new NullPointerException("ZUGFeRD conformance level");
}
this.profile = zUGFeRDConformanceLevel;
} }
/** public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
* Sets the ZUGFeRD profile. return true;
*
* @param zUGFeRDConformanceLevel the new conformance level
* @deprecated Use {@link #setConformanceLevel(PDFAConformanceLevel)} instead
*/
@Deprecated
public void setZUGFeRDConformanceLevel(String zUGFeRDConformanceLevel) {
this.profile = ZUGFeRDConformanceLevel.valueOf(zUGFeRDConformanceLevel);
} }
/** private static byte[] readAllBytes(InputStream in) throws IOException {
* * ByteArrayOutputStream buffer = new ByteArrayOutputStream();
* Returns the PDFBox PDF Document IOUtils.copy(in, buffer);
* return buffer.toByteArray();
* @return PDDocument the PDFBox PDF
*/
public PDDocument getDoc() {
return doc;
} }
/**
* All files are PDF/A-3, setConformance refers to the level conformance.
* <p>
* PDF/A-3 has three coformance levels, called "A", "U" and "B".
* <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>
* Feel free to pass "A" as new level if you know what you are doing :-)
*/
public ZUGFeRDExporterFromA3 setConformanceLevel(PDFAConformanceLevel newLevel) {
conformanceLevel = newLevel;
return this;
}
public ZUGFeRDExporterFromA3 setCreator(String creator) {
this.creator = creator;
return this;
}
public ZUGFeRDExporterFromA3 setCreatorTool(String creatorTool) {
this.creatorTool = creatorTool;
return this;
}
public ZUGFeRDExporterFromA3 setProducer(String producer) {
this.producer = producer;
return this;
}
protected ZUGFeRDExporterFromA3 setAttachZUGFeRDHeaders(boolean attachHeaders) {
this.attachZUGFeRDHeaders = attachHeaders;
return this;
}
/** /**
* This will add both the RDF-indication which embedded file is Zugferd and the * This will add both the RDF-indication which embedded file is Zugferd and the
* neccessary PDF/A schema extension description to be able to add this * neccessary PDF/A schema extension description to be able to add this
@@ -595,9 +447,9 @@ public class ZUGFeRDExporter implements Closeable {
protected void addXMP(XMPMetadata metadata) { protected void addXMP(XMPMetadata metadata) {
if (attachZUGFeRDHeaders) { if (attachZUGFeRDHeaders) {
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, ZFVersion, isFacturX, profile, XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, ZFVersion, isFacturX, xmlProvider.getProfile(),
getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion), getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion),
getFilenameForVersion(ZFVersion)); getFilenameForVersion(ZFVersion, xmlProvider.getProfile()));
metadata.addSchema(zf); metadata.addSchema(zf);
} }
@@ -607,27 +459,6 @@ public class ZUGFeRDExporter implements Closeable {
metadata.addSchema(pdfaex); metadata.addSchema(pdfaex);
} }
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
XmpSerializer serializer = new XmpSerializer();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
String prefix = "<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>";
String suffix = "<?xpacket end=\"w\"?>";
try {
buffer.write(prefix.getBytes("UTF-8")); // see https://github.com/ZUGFeRD/mustangproject/issues/44
serializer.serialize(xmpMetadata, buffer, false);
buffer.write(suffix.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e)
{
throw new TransformerException(e);
} catch (IOException e)
{
throw new TransformerException(e);
}
return buffer.toByteArray();
}
protected void prepareDocument() throws IOException { protected void prepareDocument() throws IOException {
String fullProducer = producer + " (via mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + ")"; String fullProducer = producer + " (via mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + ")";
@@ -659,7 +490,7 @@ public class ZUGFeRDExporter implements Closeable {
pdf.setProducer(fullProducer); pdf.setProducer(fullProducer);
if (ensurePDFisUpgraded) { if (ensurePDFisUpgraded) {
try { try {
pdfaid.setConformance(conformanceLevel.getLetter());// $NON-NLS-1$ //$NON-NLS-1$ pdfaid.setConformance(conformanceLevel.getLetter());// $NON-NLS-1$
} catch (BadFieldValueException ex) { } catch (BadFieldValueException ex) {
// This should be impossible, because it would occur only if an illegal // This should be impossible, because it would occur only if an illegal
// conformance level is supplied, // conformance level is supplied,
@@ -684,6 +515,55 @@ public class ZUGFeRDExporter implements Closeable {
documentPrepared = true; documentPrepared = true;
} }
/**
* Embeds the Zugferd XML structure in a file named ZUGFeRD-invoice.xml.
*
* @param trans a IZUGFeRDExportableTransaction that provides the data-model to
* 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 IExporter setTransaction(IExportableTransaction trans) throws IOException {
this.trans = trans;
return prepare();
}
public IExporter prepare() throws IOException{
prepareDocument();
xmlProvider.generateXML(trans);
String filename = getFilenameForVersion(ZFVersion, xmlProvider.getProfile());
PDFAttachGenericFile(doc, filename, "Alternative",
"Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)",
"text/xml", xmlProvider.getXML());
for (FileAttachment attachment: fileAttachments) {
PDFAttachGenericFile(doc, attachment.getFilename(), attachment.getRelation(), attachment.getDescription(), attachment.getMimetype(), attachment.getData());
}
return this;
}
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
XmpSerializer serializer = new XmpSerializer();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
String prefix = "<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>";
String suffix = "<?xpacket end=\"w\"?>";
try {
buffer.write(prefix.getBytes("UTF-8")); // see https://github.com/ZUGFeRD/mustangproject/issues/44
serializer.serialize(xmpMetadata, buffer, false);
buffer.write(suffix.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new TransformerException(e);
} catch (IOException e) {
throw new TransformerException(e);
}
return buffer.toByteArray();
}
/** /**
* @return if pdf file will be automatically closed after adding ZF * @return if pdf file will be automatically closed after adding ZF
*/ */
@@ -694,64 +574,31 @@ public class ZUGFeRDExporter implements Closeable {
/** /**
* @param disableAutoClose prevent PDF file from being closed after adding ZF * @param disableAutoClose prevent PDF file from being closed after adding ZF
*/ */
public void disableAutoClose(boolean disableAutoClose) { public ZUGFeRDExporterFromA3 disableAutoClose(boolean disableAutoClose) {
this.disableAutoClose = disableAutoClose; this.disableAutoClose = disableAutoClose;
return this;
} }
/** protected void setXMLProvider(IXMLProvider p) {
* the human author (use factory method instead) this.xmlProvider = p;
* if (profile!=null) {
* @param creator the (human) name who created the PDF xmlProvider.setProfile(profile);
*/ }
@Deprecated }
public void setCreator(String creator) { @Override
this.creator = creator; public ZUGFeRDExporterFromA3 setZUGFeRDVersion(int version) {
this.ZFVersion = version;
if (version == 1) {
ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider();
disableFacturX();
setXMLProvider(z1p);
} else if (version == 2) {
ZUGFeRD2PullProvider z2p = new ZUGFeRD2PullProvider();
setXMLProvider(z2p);
} else {
throw new IllegalArgumentException("Version not supported");
} }
/** return this;
* the CreatorTool attribute for the PDF
*
* @param creatorTool the application which created the PDF
*/
protected void setCreatorTool(String creatorTool) {
this.creatorTool = creatorTool;
}
/**
* the authoring software (use factory method instead)
*
* @param producer the authoring software
*/
@Deprecated
public void setProducer(String producer) {
this.producer = producer;
}
/**
* @param ensurePDFisUpgraded if not set the PDF/A won't be relabelled A/3, e.g. if it already is one
*/
public void setPDFA3(boolean ensurePDFisUpgraded) {
this.ensurePDFisUpgraded = ensurePDFisUpgraded;
}
/**
* @param attachZUGFeRDHeaders if false the ZUGFeRD XMP metadata won't be added, e.g. if it's not the first file
*/
public void setAttachZUGFeRDHeaders(boolean attachZUGFeRDHeaders) {
this.attachZUGFeRDHeaders = attachZUGFeRDHeaders;
}
/**
* encapsulate the deprecated setters
* @param zfVersion 1 or 2
* @param zugferdConformanceLevel BASIC, COMFORT, EN16931, etc.
* @param creator PDF creator
* @param producer PDF producer
*/
public void configure(int zfVersion, ZUGFeRDConformanceLevel zugferdConformanceLevel, String creator, String producer) {
setZUGFeRDVersion(zfVersion);
setZUGFeRDConformanceLevel(zugferdConformanceLevel);
setCreator(creator);
setProducer(producer);
} }
} }

View File

@@ -1,208 +0,0 @@
/** **********************************************************************
*
* 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 org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.preflight.PreflightDocument;
import org.apache.pdfbox.preflight.exception.ValidationException;
import org.apache.pdfbox.preflight.parser.PreflightParser;
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import java.io.*;
import java.util.HashMap;
public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
protected boolean ignorePDFAErrors = false;
protected ZUGFeRDConformanceLevel zugferdConformanceLevel = ZUGFeRDConformanceLevel.EXTENDED;
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
/**
* Producer (attribute for PDF
*/
protected String producer = "mustangproject";
/**
* Human creator (attribute for PDF)
*/
protected String creator = "mustangproject";
/**
* Creator tool (attribute for PDF)
*/
protected String creatorTool = null;
private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
protected int ZFVersion = ZUGFeRDExporter.DefaultZUGFeRDVersion;
protected boolean ensurePDFisUpgraded = false;
private boolean attachZUGFeRDHeaders = true;
/**
* 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 pdfFilename filename of an PDF/A1 compliant document
*/
public ZUGFeRDExporter load(String pdfFilename) throws IOException {
ensurePDFIsValidPDFA(new FileDataSource(pdfFilename));
try (FileInputStream pdf = new FileInputStream(pdfFilename)) {
return load(readAllBytes(pdf));
}
}
/**
* 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 pdfBinary binary of a PDF/A1 compliant document
*/
public ZUGFeRDExporter load(byte[] pdfBinary) throws IOException {
ensurePDFIsValidPDFA(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
PDDocument doc = PDDocument.load(pdfBinary);
ZUGFeRDExporter zugFeRDExporter = new ZUGFeRDExporter(doc);
zugFeRDExporter.configure(ZFVersion, zugferdConformanceLevel, creator, producer);
zugFeRDExporter.setAttachZUGFeRDHeaders(attachZUGFeRDHeaders);
zugFeRDExporter.setPDFA3(ensurePDFisUpgraded);
return zugFeRDExporter;
}
public ZUGFeRDExporterFromA3Factory() {
ensurePDFisUpgraded = false;
}
/**
* 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 pdfSource source to read a PDF/A1 compliant document from
*/
public ZUGFeRDExporter load(InputStream pdfSource) throws IOException {
return load(readAllBytes(pdfSource));
}
private void ensurePDFIsValidPDFA(final DataSource dataSource) throws IOException {
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
throw new IOException("File is not a valid PDF/A input file");
}
}
private static byte[] readAllBytes(InputStream in) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
IOUtils.copy(in, buffer);
return buffer.toByteArray();
}
private static boolean isValidA1(DataSource dataSource) throws IOException {
return getPDFAParserValidationResult(new PreflightParser(dataSource));
}
/**
* Sets the ZUGFeRD conformance level (override).
*
* @param zugferdConformanceLevel the new conformance level
*/
public IExporterFactory setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zugferdConformanceLevel) {
this.zugferdConformanceLevel = zugferdConformanceLevel;
return this;
}
private static boolean getPDFAParserValidationResult(PreflightParser parser) throws IOException {
/*
* Parse the PDF file with PreflightParser that inherits from the
* NonSequentialParser. Some additional controls are present to check a set of
* PDF/A requirements. (Stream length consistency, EOL after some Keyword...)
*/
parser.parse();// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
try (PreflightDocument document = parser.getPreflightDocument()) {
/*
* Once the syntax validation is done, the parser can provide a
* PreflightDocument (that inherits from PDDocument) This document process the
* end of PDF/A validation.
*/
document.validate();
// Get validation result
return document.getResult().isValid();
} catch (ValidationException e) {
/*
* the parse method can throw a SyntaxValidationException if the PDF file can't
* be parsed. In this case, the exception contains an instance of
* ValidationResult
*/
return false;
}
}
/**
* All files are PDF/A-3, setConformance refers to the level conformance.
* <p>
* PDF/A-3 has three coformance levels, called "A", "U" and "B".
* <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>
* Feel free to pass "A" as new level if you know what you are doing :-)
*/
public IExporterFactory setConformanceLevel(PDFAConformanceLevel newLevel) {
conformanceLevel = newLevel;
return this;
}
public IExporterFactory ignorePDFAErrors() {
this.ignorePDFAErrors = true;
return this;
}
public IExporterFactory setCreator(String creator) {
this.creator = creator;
return this;
}
public IExporterFactory setCreatorTool(String creatorTool) {
this.creatorTool = creatorTool;
return this;
}
public IExporterFactory setProducer(String producer) {
this.producer = producer;
return this;
}
public IExporterFactory setAttachZUGFeRDHeaders(boolean attachHeaders) {
this.attachZUGFeRDHeaders = attachHeaders;
return this;
}
@Override
public IExporterFactory setZUGFeRDVersion(int version) {
this.ZFVersion = version;
return this;
}
}

View File

@@ -30,6 +30,8 @@ import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*; import javax.xml.xpath.*;
import org.mustangproject.Item;
import org.mustangproject.Product;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary; import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode; import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
@@ -135,7 +137,7 @@ public class ZUGFeRDImporter {
/** /**
* filenames for invoice data (ZUGFeRD v1 and v2, Factur-X) * filenames for invoice data (ZUGFeRD v1 and v2, Factur-X)
*/ */
if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml"))) { //$NON-NLS-1$ if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml")) || filename.equals("xrechnung.xml") || filename.equals("order-x.xml")) {
containsMeta = true; containsMeta = true;
PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile(); PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
@@ -231,9 +233,9 @@ public class ZUGFeRDImporter {
return result; return result;
} }
/***
/** * Wrapper for protected method extractString
* Wrapper for protected method exracteString * @param xpathStr the xpath expression to be evaluated
* @return the extracted String for the specific path in the document * @return the extracted String for the specific path in the document
*/ */
public String wExtractString(String xpathStr) { public String wExtractString(String xpathStr) {
@@ -252,6 +254,250 @@ public class ZUGFeRDImporter {
return result; return result;
} }
/**
* @return the ZUGFeRD Profile
*/
public String getZUGFeRDProfil() {
switch (extractString("//GuidelineSpecifiedDocumentContextParameter//ID")) {
case "urn:cen.eu:en16931:2017":
case "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort":
return "COMFORT";
case "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic":
case "urn:ferd:CrossIndustryDocument:invoice:1p0:basic":
return "BASIC";
case "urn:factur-x.eu:1p0:basicwl":
return "BASIC WL";
case "urn:factur-x.eu:1p0:minimum":
return "MINIMUM";
case "urn:ferd:CrossIndustryDocument:invoice:1p0:extended":
case "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended":
return "EXTENDED";
}
return "";
}
/**
* @return the Invoice Currency Code
*/
public String getInvoiceCurrencyCode() {
try {
if (getVersion() == 1) {
return extractString("//ApplicableSupplyChainTradeSettlement//InvoiceCurrencyCode");
} else {
return extractString("//ApplicableHeaderTradeSettlement//InvoiceCurrencyCode");
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* @return the IssuerAssigned ID
*/
public String getIssuerAssignedID() {
try {
if (getVersion() == 1) {
return extractString("//BuyerOrderReferencedDocument//ID");
} else {
return extractString("//BuyerOrderReferencedDocument//IssuerAssignedID");
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* @return the BuyerTradeParty ID
*/
public String getBuyerTradePartyID() {
return extractString("//BuyerTradeParty//ID");
}
/**
* @return the Issue Date()
*/
public String getIssueDate() {
try {
if (getVersion() == 1) {
return extractString("//HeaderExchangedDocument//IssueDateTime//DateTimeString");
} else {
return extractString("//ExchangedDocument//IssueDateTime//DateTimeString");
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* @return the TaxBasisTotalAmount
*/
public String getTaxBasisTotalAmount() {
try {
if (getVersion() == 1) {
return extractString("//SpecifiedTradeSettlementMonetarySummation//TaxBasisTotalAmount");
} else {
return extractString("//SpecifiedTradeSettlementHeaderMonetarySummation//TaxBasisTotalAmount");
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* @return the TaxTotalAmount
*/
public String getTaxTotalAmount() {
try {
if (getVersion() == 1) {
return extractString("//SpecifiedTradeSettlementMonetarySummation//TaxTotalAmount");
} else {
return extractString("//SpecifiedTradeSettlementHeaderMonetarySummation//TaxTotalAmount");
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* @return the RoundingAmount
*/
public String getRoundingAmount() {
try {
if (getVersion() == 1) {
return extractString("//SpecifiedTradeSettlementMonetarySummation//RoundingAmount");
} else {
return extractString("//SpecifiedTradeSettlementHeaderMonetarySummation//RoundingAmount");
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* @return the TotalPrepaidAmount
*/
public String getPaidAmount() {
try {
if (getVersion() == 1) {
return extractString("//SpecifiedTradeSettlementMonetarySummation//TotalPrepaidAmount");
} else {
return extractString("//SpecifiedTradeSettlementHeaderMonetarySummation//TotalPrepaidAmount");
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* @return SellerTradeParty GlobalID
*/
public String getSellerTradePartyGlobalID() {
return extractString("//SellerTradeParty//GlobalID");
}
/**
* @return the BuyerTradeParty GlobalID
*/
public String getBuyerTradePartyGlobalID() {
return extractString("//BuyerTradeParty//GlobalID");
}
/**
* @return the BuyerTradeParty SpecifiedTaxRegistration ID
*/
public String getBuyertradePartySpecifiedTaxRegistrationID() {
return extractString("//BuyerTradeParty//SpecifiedTaxRegistration//ID");
}
/**
* @return the IncludedNote
*/
public String getIncludedNote() {
try {
if (getVersion() == 1) {
return extractString("//HeaderExchangedDocument//IncludedNote");
} else {
return extractString("//ExchangedDocument//IncludedNote");
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* @return the BuyerTradeParty Name
*/
public String getBuyerTradePartyName() {
return extractString("//BuyerTradeParty//Name");
}
/**
* @return the line Total Amount
*/
public String getLineTotalAmount() {
try {
if (getVersion() == 1) {
return extractString("//SpecifiedTradeSettlementMonetarySummation//LineTotalAmount");
} else {
return extractString("//SpecifiedTradeSettlementHeaderMonetarySummation//LineTotalAmount");
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* @return the Payment Terms
*/
public String getPaymentTerms() {
return extractString("//SpecifiedTradePaymentTerms//Description");
}
/**
* @return the Taxpoint Date
*/
public String getTaxPointDate() {
try {
if (getVersion() == 1) {
return extractString("//ActualDeliverySupplyChainEvent//OccurrenceDateTime//DateTimeString");
} else {
return extractString("//ActualDeliverySupplyChainEvent//OccurrenceDateTime//DateTimeString");
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/**
* @return the Invoice ID
*/
public String getInvoiceID() {
try {
if (getVersion() == 1) {
return extractString("//HeaderExchangedDocument//ID");
} else {
return extractString("//ExchangedDocument//ID");
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
/** /**
* @return the document code * @return the document code
@@ -442,7 +688,7 @@ public class ZUGFeRDImporter {
// SpecifiedExchangedDocumentContext is in the schema, so a relatively good // SpecifiedExchangedDocumentContext is in the schema, so a relatively good
// indication if zugferd is present - better than just invoice // indication if zugferd is present - better than just invoice
String meta = getMeta(); String meta = getMeta();
return (meta != null) && (meta.length() > 0) && ((meta.contains("SpecifiedExchangedDocumentContext") //$NON-NLS-1$ return (meta != null) && (meta.length() > 0) && ((meta.contains("SpecifiedExchangedDocumentContext")
/* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */)); /* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */));
} }
@@ -454,6 +700,28 @@ public class ZUGFeRDImporter {
return s.hasNext() ? s.next() : ""; return s.hasNext() ? s.next() : "";
} }
/**
* returns an instance of PostalTradeAddress for SellerTradeParty section
* @return an instance of PostalTradeAddress
*/
public PostalTradeAddress getBuyerTradePartyAddress() {
NodeList nl = null;
try {
if (getVersion() == 1) {
nl = getNodeListByPath("//CrossIndustryDocument//SpecifiedSupplyChainTradeTransaction//ApplicableSupplyChainTradeAgreement//BuyerTradeParty//PostalTradeAddress");
} else {
nl = getNodeListByPath("//CrossIndustryInvoice//SupplyChainTradeTransaction//ApplicableHeaderTradeAgreement//BuyerTradeParty//PostalTradeAddress");
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return getAddressFromNodeList(nl);
}
/** /**
* returns an instance of PostalTradeAddress for SellerTradeParty section * returns an instance of PostalTradeAddress for SellerTradeParty section
* @return an instance of PostalTradeAddress * @return an instance of PostalTradeAddress
@@ -471,9 +739,15 @@ public class ZUGFeRDImporter {
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return address; return null;
} }
return getAddressFromNodeList(nl);
}
private PostalTradeAddress getAddressFromNodeList(NodeList nl) {
PostalTradeAddress address = new PostalTradeAddress();
if (nl != null) { if (nl != null) {
for (int i = 0; i < nl.getLength(); i++) { for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i); Node n = nl.item(i);
@@ -484,25 +758,46 @@ public class ZUGFeRDImporter {
if (nodeType==Node.ELEMENT_NODE){ if (nodeType==Node.ELEMENT_NODE){
switch (n.getNodeName()) { switch (n.getNodeName()) {
case "ram:PostcodeCode": case "ram:PostcodeCode":
address.setPostCodeCode("");
if (n.getFirstChild() != null) {
address.setPostCodeCode(n.getFirstChild().getNodeValue()); address.setPostCodeCode(n.getFirstChild().getNodeValue());
}
break; break;
case "ram:LineOne": case "ram:LineOne":
address.setLineOne("");
if (n.getFirstChild() != null) {
address.setLineOne(n.getFirstChild().getNodeValue()); address.setLineOne(n.getFirstChild().getNodeValue());
}
break; break;
case "ram:LineTwo": case "ram:LineTwo":
address.setLineTwo("");
if (n.getFirstChild() != null) {
address.setLineTwo(n.getFirstChild().getNodeValue()); address.setLineTwo(n.getFirstChild().getNodeValue());
}
break; break;
case "ram:LineThree": case "ram:LineThree":
address.setLineThree("");
if (n.getFirstChild() != null) {
address.setLineThree(n.getFirstChild().getNodeValue()); address.setLineThree(n.getFirstChild().getNodeValue());
}
break; break;
case "ram:CityName": case "ram:CityName":
address.setCityName("");
if (n.getFirstChild() != null) {
address.setCityName(n.getFirstChild().getNodeValue()); address.setCityName(n.getFirstChild().getNodeValue());
}
break; break;
case "ram:CountryID": case "ram:CountryID":
address.setCountryID("");
if (n.getFirstChild() != null) {
address.setCountryID(n.getFirstChild().getNodeValue()); address.setCountryID(n.getFirstChild().getNodeValue());
}
break; break;
case "ram:CountrySubDivisionName": case "ram:CountrySubDivisionName":
address.setCountrySubDivisionName("");
if (n.getFirstChild() != null) {
address.setCountrySubDivisionName(n.getFirstChild().getNodeValue()); address.setCountrySubDivisionName(n.getFirstChild().getNodeValue());
}
break; break;
} }
} }
@@ -512,7 +807,6 @@ public class ZUGFeRDImporter {
return address; return address;
} }
/** /**
* returns a list of LineItems * returns a list of LineItems
* @return a List of LineItem instances * @return a List of LineItem instances
@@ -556,16 +850,16 @@ public class ZUGFeRDImporter {
case "ram:SpecifiedTradeProduct": case "ram:SpecifiedTradeProduct":
node = getNodeByName(nn.getChildNodes(), "ram:SellerAssignedID"); node = getNodeByName(nn.getChildNodes(), "ram:SellerAssignedID");
lineItem.product.setSellerAssignedID(getNodeValue(node)); lineItem.getProduct().setSellerAssignedID(getNodeValue(node));
node = getNodeByName(nn.getChildNodes(), "ram:BuyerAssignedID"); node = getNodeByName(nn.getChildNodes(), "ram:BuyerAssignedID");
lineItem.product.setBuyerAssignedID(getNodeValue(node)); lineItem.getProduct().setBuyerAssignedID(getNodeValue(node));
node = getNodeByName(nn.getChildNodes(), "ram:Name"); node = getNodeByName(nn.getChildNodes(), "ram:Name");
lineItem.product.setName(getNodeValue(node)); lineItem.getProduct().setName(getNodeValue(node));
node = getNodeByName(nn.getChildNodes(), "ram:Description"); node = getNodeByName(nn.getChildNodes(), "ram:Description");
lineItem.product.setDescription(getNodeValue(node)); lineItem.getProduct().setDescription(getNodeValue(node));
break; break;
case "ram:SpecifiedLineTradeDelivery": case "ram:SpecifiedLineTradeDelivery":
@@ -579,7 +873,7 @@ public class ZUGFeRDImporter {
node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax"); node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax");
if (node != null) { if (node != null) {
node = getNodeByName(node.getChildNodes(), "ram:RateApplicablePercent"); node = getNodeByName(node.getChildNodes(), "ram:RateApplicablePercent");
lineItem.product.setVATPercent(tryBigDecimal(getNodeValue(node))); lineItem.getProduct().setVATPercent(tryBigDecimal(getNodeValue(node)));
} }
node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax"); node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax");
@@ -600,7 +894,7 @@ public class ZUGFeRDImporter {
node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax"); node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax");
if (node != null) { if (node != null) {
node = getNodeByName(node.getChildNodes(), "ram:ApplicablePercent"); node = getNodeByName(node.getChildNodes(), "ram:ApplicablePercent");
lineItem.product.setVATPercent(tryBigDecimal(getNodeValue(node))); lineItem.getProduct().setVATPercent(tryBigDecimal(getNodeValue(node)));
} }
node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax"); node = getNodeByName(nn.getChildNodes(), "ram:ApplicableTradeTax");

View File

@@ -1,31 +1,41 @@
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import org.w3c.dom.Document; import org.mustangproject.*;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import javax.xml.xpath.*; import javax.xml.xpath.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter { public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
public ZUGFeRDInvoiceImporter(String filename) { public ZUGFeRDInvoiceImporter(String filename) {
super(filename); super(filename);
} }
public ZUGFeRD2PushProvider extractInvoice() {
public Invoice extractInvoice() {
String number = "AB123"; String number = "AB123";
ZUGFeRD2PushProvider zpp=new ZUGFeRD2PushProvider().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setOwnStreet("teststr").setOwnZIP("55232").setOwnLocation("teststadt").setOwnCountry("DE").setOwnTaxID("4711").setOwnVATID("0815").setRecipient(new Contact("Franz Müller", "0177123456", "fmueller@test.com", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number); /**
* dummywerte sind derzeit noch setDueDate setIssueDate setDeliveryDate setSender setRecipient setnumber
* bspw. due date //ExchangedDocument//IssueDateTime//DateTimeString : due date optional
*/
XPathFactory xpathFact = XPathFactory.newInstance();
XPath xpath = xpathFact.newXPath();
Invoice zpp = null;
try {
XPathExpression xpr = xpath.compile(
"//SellerTradeParty");
NodeList SellerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
xpr = xpath.compile(
"//BuyerTradeParty");
NodeList BuyerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
zpp= new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number);
//.addItem(new Item(new Product("Testprodukt","","C62",new BigDecimal(0)),amount,new BigDecimal(1.0))) //.addItem(new Item(new Product("Testprodukt","","C62",new BigDecimal(0)),amount,new BigDecimal(1.0)))
zpp.setOwnOrganisationName(extractString("//SellerTradeParty/Name")); zpp.setOwnOrganisationName(extractString("//SellerTradeParty/Name"));
XPathFactory xpathFact = XPathFactory.newInstance(); xpr = xpath.compile(
XPath xpath = xpathFact.newXPath();
try {
XPathExpression xpr = xpath.compile(
"//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]"); "//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]");
NodeList nodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); NodeList nodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
@@ -36,6 +46,7 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
Node currentItemNode = nodes.item(i); Node currentItemNode = nodes.item(i);
NodeList itemChilds = currentItemNode.getChildNodes(); NodeList itemChilds = currentItemNode.getChildNodes();
String price = "0"; String price = "0";
String quantity = "0";
for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) { for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) {
if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeAgreement")) { if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeAgreement")) {
NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes(); NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes();
@@ -51,10 +62,18 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
} }
} }
} }
if (itemChilds.item(itemChildIndex).getNodeName().equals("ram:SpecifiedLineTradeDelivery")) {
NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes();
for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds.getLength(); tradeLineChildIndex++) {
if (tradeLineChilds.item(tradeLineChildIndex).getNodeName().equals("ram:BilledQuantity")) {
quantity = tradeLineChilds.item(tradeLineChildIndex).getTextContent();
}
}
}
} }
// Logger.getLogger(ZUGFeRDInvoiceImporter.class.getName()).log(Level.INFO, "deb "+price); // Logger.getLogger(ZUGFeRDInvoiceImporter.class.getName()).log(Level.INFO, "deb "+price);
// dummywerte sind derzeit noch produkname, beschreibung, unit, VAT percent, menge
zpp.addItem(new Item(new Product("Testprodukt","","C62",new BigDecimal(0)),new BigDecimal(price),new BigDecimal(1.0))); zpp.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(0)), new BigDecimal(price), new BigDecimal(quantity)));
} }
} }

View File

@@ -32,12 +32,12 @@ import java.util.logging.Logger;
public class ZUGFeRDVisualizer { public class ZUGFeRDVisualizer {
static final ClassLoader CLASS_LOADER = ZUGFeRDVisualizer.class.getClassLoader(); static final ClassLoader CLASS_LOADER = ZUGFeRDVisualizer.class.getClassLoader();
private static final String RESOURCE_PATH = ""; //$NON-NLS-1$ private static final String RESOURCE_PATH = "";
private static final Logger LOG = Logger.getLogger(ZUGFeRDVisualizer.class.getName()); private static final Logger LOG = Logger.getLogger(ZUGFeRDVisualizer.class.getName());
// private static File createTempFileResult(final Transformer transformer, final // private static File createTempFileResult(final Transformer transformer, final
// StreamSource toTransform, // StreamSource toTransform,
// final String suffix) throws TransformerException, IOException { // final String suffix) throws TransformerException, IOException {
// File result = File.createTempFile("ZUV_", suffix); //$NON-NLS-1$ // File result = File.createTempFile("ZUV_", suffix);
// result.deleteOnExit(); // result.deleteOnExit();
// //
// try (FileOutputStream fos = new FileOutputStream(result)) { // try (FileOutputStream fos = new FileOutputStream(result)) {

View File

@@ -21,5 +21,6 @@ package org.mustangproject.ZUGFeRD.model;
public class DocumentCodeTypeConstants { public class DocumentCodeTypeConstants {
public static final String INVOICE = "380"; public static final String INVOICE = "380";
public static final String DEBITNOTE = "84"; public static final String DEBITNOTE = "84";
public static final String CORRECTEDINVOICE = "384";
public static final String CREDITNOTE = "389"; public static final String CREDITNOTE = "389";
} }

View File

@@ -0,0 +1,30 @@
<configuration>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Daily rollover -->
<fileNamePattern>log/ZUV-%d{yyyy-MM}.log</fileNamePattern>
<!-- Keep 5 years worth of history -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Configure so that it outputs to both console and log file -->
<root level="INFO">
<appender-ref ref="FILE" />
<appender-ref ref="STDERR" />
</root>
</configuration>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,917 @@
/* Grundformatierung ********************************************/
*,
*:after,
*:before
{
box-sizing: border-box;
-moz-box-sizing: border-box;
}
.clear:after
{
content: ".";
clear: both;
display: block;
visibility: hidden;
height: 0;
}
html,
body
{
height: 100%;
min-width: 320px;
margin: 0;
padding: 0;
color: #000;
font-size: 14px;
}
body
{
overflow-y: scroll;
background-color: rgba(4, 101, 161, 0.08);
}
h4
{
color: inherit;
font-size: inherit;
margin-bottom: 0.5rem;
}
/* Grundaufbau *************************************************/
.menue
{
position: relative;
z-index: 2000;
background-color: #000;
margin-bottom: 30px;
}
.innen
{
max-width: 1080px;
margin: 0 auto;
padding: 0 2%;
}
/* Formatierungen *************************************************/
.color2
{
color: rgba(0, 0, 0, 0.6);
}
.schwarz
{
color: #555 !important;
}
.normal
{
font-weight: normal;
}
.bold
{
font-weight: bold;
}
.abstandUnten
{
margin-bottom: 5px;
}
.abstandUntenKlein
{
margin-bottom: 10px;
}
.noPaddingTop
{
padding-top: 0 !important;
}
.ausrichtungRechts
{
text-align: right;
}
/* Menü ********************************************************/
button
{
position: relative;
font-family: serif;
padding-top: 15px;
padding-left: 0;
padding-right: 0;
margin-right: 2%;
}
.btnAktiv
{
font-size: 22px;
color: #ffb619;
height: 50px;
outline: none;
border: none;
background: none;
}
.btnAktiv:after
{
content: "";
display: block;
position: absolute;
top: 50px;
left: 50%;
z-index: 10;
font-size: 0;
line-height: 0;
height: 0;
padding: 0;
margin: 0;
transform: translateX(-50%);
border: 15px solid #000;
border-right-color: transparent;
border-bottom-color: transparent;
border-left-color: transparent;
}
.btnInaktiv,
.tab
{
font-size: 22px;
color: #fff;
height: 50px;
z-index: 0;
outline: none;
border: none;
background: none;
transition: color 0.3s ease;
}
.btnInaktiv:hover,
.tab:hover
{
color: #ffb619;
cursor: pointer;
}
.divHide
{
display: none;
}
/* Content *********************************************************************/
.inhalt
{
font-family: sans-serif;
margin-bottom: 30px;
}
.haftungausschluss
{
color: #000;
text-align: center;
padding: 7px;
margin-bottom: 30px;
width: 100%;
border: 1px solid #ffb619;
background-color: #fff;
}
.box
{
position: relative;
display: table-cell;
padding: 0;
border: 1px solid rgba(4, 101, 161, 0.2);
background-color: #fff;
}
.subBox
{
border-top: none;
width: 50%;
}
.subBox:last-child
{
border-left: none;
}
.first > .boxzeile > .subBox
{
border-top: 1px solid rgba(4, 101, 161, 0.2) !important;
}
.boxtitel
{
display: inline-block;
background-color: #0465A1;
padding: 7px 10px;
color: #fff;
font-weight: bold;
}
.boxBorderTop
{
border-top: none;
}
.boxBorderLeft
{
border-left: none;
}
.boxtitelSub
{
color: #000;
background-color: rgba(4, 101, 161, 0.1);
border-right: 1px solid rgba(4, 101, 161, 0.2);
border-bottom: 1px solid rgba(4, 101, 161, 0.2);
}
.boxinhalt
{
padding: 15px 20px;
}
.boxtabelle
{
display: table;
width: 100%;
}
.borderSpacing
{
border-spacing: 0 5px;
}
.boxabstandtop
{
margin-top: 30px;
}
.boxzeile
{
display: table-row;
}
.boxzeile .box:last-child
{
margin-bottom: 0;
}
.boxdaten
{
display: table-cell;
padding: 5px 0;
vertical-align: middle;
height: 38px;
/*
-ms-word-break: break-all;
word-break: break-all;
word-break: break-word;
-webkit-hyphens: auto;
-moz-hyphens: auto;
hyphens: auto;
*/
}
.boxdaten.wert
{
padding: 5px 10px;
}
.boxcell
{
display: table-cell;
}
.boxdatenBlock
{
display: block;
padding: 3px 0;
/*
-ms-word-break: break-all;
word-break: break-all;
word-break: break-word;
-webkit-hyphens: auto;
-moz-hyphens: auto;
hyphens: auto;
*/
}
.noBreak
{
-ms-word-break: keep-all;
word-break: keep-all;
word-break: keep-all;
-webkit-hyphens: none;
-moz-hyphens: none;
hyphens: none;
}
.boxabstand
{
display: table-cell;
width: 30px;
}
.legende
{
color: rgba(0, 0, 0, 0.6);
width: 170px;
font-size: 13px;
line-height: 16px;
padding-right: 5px;
}
.wert
{
background-color: rgba(4, 101, 161, 0.03);
}
.boxtabelleEinspaltig
{
width: 49%;
}
.boxtabelleZweispaltig,
.boxtabelleDreispaltig
{
width: 100%;
}
.box5050
{
width: 50%;
}
.boxEinspaltig
{
width: 100%;
}
.boxZweispaltig
{
width: 48.5%;
}
.boxSpalte1 {
width: 50%;
}
.boxSpalte2 {
width: 50%;
padding-left: 20px;
}
.paddingLeft {
padding-left: 0.1em;
}
.noPadding {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
.rechnungsZeile
{
display: table-row;
}
.rechnungsZeile .boxdaten
{
height: auto;
}
.rechnungSp1
{
width: 65%;
font-size: 16px;
}
.rechnungSp2
{
width: 10%;
}
.rechnungSp3
{
width: 25%;
font-size: 16px;
text-align: right;
}
.detailSp1,
.detailSp2
{
width: 50%;
}
.detailSp2
{
text-align: right;
}
.line1Bottom
{
border-bottom: 1px solid #000;
}
.line1BottomLight
{
padding-bottom: 5px;
border-bottom: 1px solid #f0f0f0;
margin-bottom: 5px;
}
.line2Bottom
{
border-bottom: 2px solid #000;
}
.paddingTop
{
padding-top: 10px;
}
.paddingBottom
{
padding-bottom: 10px;
}
.grund
{
font-size: 16px;
display: block;
width: 100%;
padding: 0 20px 15px 20px;
}
.grundDetail
{
display: block;
width: 100%;
padding: 0 20px 15px 20px;
}
/* Übersichtformatierungen */
#uebersichtLastschrift.box,
#uebersichtUeberweisung.box
{
border-top: none;
}
#uebersichtUeberweisung.box
{
border-left: none;
}
/* Formatierungen Detailseite */
.detailsSpalte1,
.detailsSpalte2
{
width: 30%;
float: left;
font-size: 90%;
line-height: 115%;
margin-right: 5%;
}
.detailsSpalte3
{
width: 30%;
float: left;
font-size: 90%;
line-height: 115%;
}
.detailsSpalte1 .legende,
.detailsSpalte2 .legende,
.detailsSpalte3 .legende
{
width: 145px;
}
.titelPosition
{
font-size: 17px;
font-weight: bold;
}
/* Laufzettelformatierungen */
#laufzettelHistorie .boxtabelle:not(:nth-child(2))
{
border-top: 1px solid rgba(4, 101, 161, 0.2);
padding-top: 10px;
margin-top: 10px;
}
/* 1023px und kleiner ************************************************/
@media screen and (max-width : 1023px) {
.box
{
display: block;
width: 100%;
margin-bottom: 20px;
}
.boxabstandtop
{
margin-top: 15px;
}
.subBox:first-child
{
margin-bottom: 0 !important;
}
.subBox:last-child
{
border-left: 1px solid rgba(4, 101, 161, 0.2);
}
.first > .boxzeile > .subBox
{
border-top: none !important;
}
.first > .boxzeile > .subBox:first-child
{
border-top: 1px solid rgba(4, 101, 161, 0.2) !important;
}
.first > .boxzeile
{
margin-bottom: 0;
}
#uebersichtUeberweisung.box
{
border-left: 1px solid rgba(4, 101, 161, 0.2);
}
#uebersichtLastschrift.box
{
margin-bottom: 0;
}
.boxzeile
{
display: block;
margin-bottom: 5px;
}
.boxzeile:after
{
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
#details > .boxtabelle > .boxzeile
{
margin-bottom: 0px;
}
.boxcell
{
display: block;
}
.boxcell:last-child
{
margin-top: 20px;
}
.boxZweispaltig
{
width: 100%;
}
.legende
{
display: block;
float: left;
width: 170px;
padding: 5px 0;
height: auto;
}
.wert
{
display: block;
float: left;
width: calc(100% - 170px);
padding: 11px 10px !important;
line-height: 1.3;
min-height: 38px;
height: auto;
}
.boxdaten .legende
{
height: auto;
}
.rechnungsZeile .boxdaten
{
padding: 5px 0;
}
.boxabstand
{
display: none;
}
.boxtabelleEinspaltig {
width: 100%;
}
.boxSpalte1 {
display: block;
width: auto;
}
.boxSpalte2 {
display: block;
width: auto;
padding-left: 0px;
margin-top: 1.2rem;
}
.detailsSpalte1,
.detailsSpalte2,
.detailsSpalte3
{
width: 100%;
float: none;
padding-right: 0px;
}
.detailsSpalte2,
.detailsSpalte3
{
margin-top: 15px;
}
.detailsSpalte2,
.detailsSpalte3
{
margin-top: 10px;
}
.tableNumberAlignRight
{
display: block;
width: 130px;
text-align: right;
}
}
/* 800px und kleiner ************************************************/
@media screen and (max-width : 800px) {
button
{
padding-top: 10px;
}
.btnAktiv,
.btnInaktiv,
.tab
{
font-size: 20px;
height: 40px;
}
.btnAktiv:after
{
top: 40px;
}
.rechnungSp1
{
width: 55%;
font-size: 15px;
}
.rechnungSp2
{
width: 10%;
}
.rechnungSp3
{
width: 35%;
text-align: right;
font-size: 15px;
}
.grund
{
font-size: 15px;
}
}
/* 450px und kleiner ************************************************/
@media screen and (max-width : 450px)
{
html,
body
{
font-size: 12px;
}
.menue
{
margin-bottom: 20px;
}
button
{
padding-top: 5px;
}
.btnAktiv,
.btnInaktiv,
.tab
{
font-size: 17px;
height: 35px;
}
.btnAktiv:after
{
top: 35px;
}
.legende
{
font-size: 12px;
width: 100%;
}
.wert
{
font-size: 12px;
line-height: 1.3;
width: 100%;
margin-bottom: 10px
}
.boxzeile
{
margin-bottom: 0px
}
.boxdaten
{
height: auto;
}
.haftungausschluss
{
margin-bottom: 20px;
}
.boxinhalt
{
margin-top: 0px;
}
.boxabstandtop
{
margin-top: 20px;
}
.boxtitel
{
padding: 7px 8px;
}
.box
{
margin-bottom: 10px;
padding: 0;
}
.boxabstandtop
{
margin-top: 10px;
}
.boxdaten,
.boxdatenBlock
{
padding: 2px 0;
}
.rechnungSp1
{
width: 50%;
font-size: inherit;
}
.rechnungSp2
{
width: 15%;
}
.rechnungSp3
{
width: 35%;
font-size: inherit;
text-align: right;
}
.grund
{
font-size: inherit;
}
.titelPosition
{
font-size: 15px;
}
.abstandUnten
{
margin-bottom: 5px;
}
.detailsSpalte1,
.detailsSpalte2,
.detailsSpalte3
{
font-size: inherit;
line-height: inherit;
}
}
/* 380px und kleiner ************************************************/
@media screen and (max-width : 380px) {
html,
body
{
font-size: 11px;
line-height: 100%;
}
.btnAktiv,
.btnInaktiv,
.tab
{
font-size: 15px;
}
.boxdaten
.boxdatenBlock
{
padding: 2px 0;
}
.boxinhalt
{
margin-top: 0px;
}
.boxtitel
{
padding: 5px 7px;
}
}

View File

@@ -0,0 +1,145 @@
/* Tab-Container aufbauen **************************************************/
var a = new Array("uebersicht", "details", "zusaetze", "anlagen", "laufzettel");
var b = new Array("menueUebersicht", "menueDetails", "menueZusaetze", "menueAnlagen", "menueLaufzettel");
function show(e) {
var i = 0;
var j = 1;
for (var t = 0; t < b.length; t++) {
if (b[t] === e.id) {
i = t;
if (i > 0) {
j = 0;
} else {
j = i + 1;
}
break;
}
}
e.setAttribute("class", "btnAktiv");
for (var k = 0; k < b.length; k++) {
if (k === i && (document.getElementById(a[k]) != null)) {
document.getElementById(a[k]).style.display = "block";
if (i === j)
j = i + 1;
} else {
if (document.getElementById(a[k]) != null) {
document.getElementById(a[j]).style.display = "none";
document.getElementById(b[j]).setAttribute("class", "btnInaktiv");
j += 1;
}
}
}
}
window.onload = function () {
document.getElementById(b[0]).setAttribute("class", "btnAktiv");
}
/* Eingebettete Binaerdaten runterladen ************************************/
function base64_to_binary (data) {
var chars = atob(data);
var bytes = new Array(chars.length);
for (var i = 0; i < chars.length; i++) {
bytes[i] = chars.charCodeAt(i);
}
return new Uint8Array(bytes);
}
function downloadData (element_id) {
var data_element = document.getElementById(element_id);
var mimetype = data_element.getAttribute('mimeType');
var filename = data_element.getAttribute('filename');
var text = data_element.innerHTML;
var binary = base64_to_binary(text);
var blob = new Blob([binary], {
type: mimetype, size: binary.length
});
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
// IE
window.navigator.msSaveOrOpenBlob(blob, filename);
} else {
// Non-IE
var url = window.URL.createObjectURL(blob);
window.open(url);
}
}
/* Polyfill IE atob/btoa ************************************/
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], function () {
factory(root);
});
} else factory(root);
// node.js has always supported base64 conversions, while browsers that support
// web workers support base64 too, but you may never know.
})(typeof exports !== "undefined" ? exports: this, function (root) {
if (root.atob) {
// Some browsers' implementation of atob doesn't support whitespaces
// in the encoded string (notably, IE). This wraps the native atob
// in a function that strips the whitespaces.
// The original function can be retrieved in atob.original
try {
root.atob(" ");
}
catch (e) {
root.atob = (function (atob) {
var func = function (string) {
return atob(String(string).replace(/[\t\n\f\r ]+/g, ""));
};
func.original = atob;
return func;
})(root.atob);
}
return;
}
// base64 character set, plus padding character (=)
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// Regular expression to check formal correctness of base64 encoded strings
b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
root.btoa = function (string) {
string = String(string);
var bitmap, a, b, c,
result = "", i = 0,
rest = string.length % 3; // To determine the final padding
for (; i < string.length;) {
if ((a = string.charCodeAt(i++)) > 255 || (b = string.charCodeAt(i++)) > 255 || (c = string.charCodeAt(i++)) > 255)
throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.");
bitmap = (a << 16) | (b << 8) | c;
result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63) + b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
}
// If there's need of padding, replace the last 'A's with equal signs
return rest ? result.slice(0, rest - 3) + "===".substring(rest): result;
};
root.atob = function (string) {
// atob can work with strings with whitespaces, even inside the encoded part,
// but only \t, \n, \f, \r and ' ', which can be stripped.
string = String(string).replace(/[\t\n\f\r ]+/g, "");
if (! b64re.test(string))
throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");
// Adding the padding if missing, for semplicity
string += "==".slice(2 - (string.length & 3));
var bitmap, result = "", r1, r2, i = 0;
for (; i < string.length;) {
bitmap = b64.indexOf(string.charAt(i++)) << 18 | b64.indexOf(string.charAt(i++)) << 12 | (r1 = b64.indexOf(string.charAt(i++))) << 6 | (r2 = b64.indexOf(string.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255): r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255): String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result;
};
});

View File

@@ -27,6 +27,7 @@ import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.mustangproject.TradeParty;
/*** /***
* This is a test to confirm the minimum steps to implement a interface are still sufficient * This is a test to confirm the minimum steps to implement a interface are still sufficient
@@ -34,7 +35,7 @@ import junit.framework.TestCase;
* @author jstaerk * @author jstaerk
* *
*/ */
public class BackwardCompatibilityTest extends TestCase implements IZUGFeRDExportableTransaction{ public class BackwardCompatibilityTest extends TestCase implements IExportableTransaction {
final String TARGET_PDF_ZF1 = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506zf1.pdf"; final String TARGET_PDF_ZF1 = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506zf1.pdf";
final String TARGET_PDF_ZF2 = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506zf2.pdf"; final String TARGET_PDF_ZF2 = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506zf2.pdf";
@@ -55,9 +56,9 @@ public class BackwardCompatibilityTest extends TestCase implements IZUGFeRDExpor
try (InputStream SOURCE_PDF = this.getClass() try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf"); .getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(1).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) { IZUGFeRDExporter ze = new ZUGFeRDExporterFromA1().setZUGFeRDVersion(1).setProfile("EN16931").load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this); ze.setTransaction(this);
ze.disableAutoClose(true); ze.disableAutoClose(true);
ze.export(TARGET_PDF_ZF1); ze.export(TARGET_PDF_ZF1);
@@ -95,9 +96,9 @@ public class BackwardCompatibilityTest extends TestCase implements IZUGFeRDExpor
try (InputStream SOURCE_PDF = this.getClass() 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)) { IZUGFeRDExporter ze = new ZUGFeRDExporterFromA1().setZUGFeRDVersion(2).setProfile("EN16931").load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this); ze.setTransaction(this);
ze.disableAutoClose(true); ze.disableAutoClose(true);
ze.export(TARGET_PDF_ZF2); ze.export(TARGET_PDF_ZF2);
@@ -133,10 +134,9 @@ public class BackwardCompatibilityTest extends TestCase implements IZUGFeRDExpor
try (InputStream SOURCE_PDF = this.getClass() 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)) { IZUGFeRDExporter ze = new ZUGFeRDExporterFromA1().setZUGFeRDVersion(2).setProfile("EN16931").load(SOURCE_PDF)) {
ze.setFacturX(); ze.setTransaction(this);
ze.PDFattachZugferdFile(this);
ze.disableAutoClose(true); ze.disableAutoClose(true);
ze.export(TARGET_PDF_FX); ze.export(TARGET_PDF_FX);
@@ -199,11 +199,6 @@ public class BackwardCompatibilityTest extends TestCase implements IZUGFeRDExpor
return "bla"; return "bla";
} }
@Override
public String getOwnBankName() {
return "bla";
}
@Override @Override
public String getOwnIBAN() { public String getOwnIBAN() {
return "bla"; return "bla";
@@ -310,8 +305,13 @@ public class BackwardCompatibilityTest extends TestCase implements IZUGFeRDExpor
@Override @Override
public IZUGFeRDExportableContact getRecipient() { public IZUGFeRDExportableTradeParty getRecipient() {
return new Contact(); return new TradeParty("name","street","zip","city","DE");
}
@Override
public IZUGFeRDExportableTradeParty getSender() {
return new TradeParty("Bei Spiel GmbH","street","zip","city","DE");
} }

View File

@@ -20,7 +20,7 @@ package org.mustangproject.ZUGFeRD;
import java.util.Date; import java.util.Date;
public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTransaction { public class IExportableTransactionImpl implements IExportableTransaction {
private String number; private String number;
private Date issueDate; private Date issueDate;
@@ -30,9 +30,8 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran
private IZUGFeRDAllowanceCharge[] zFCharges; private IZUGFeRDAllowanceCharge[] zFCharges;
private IZUGFeRDAllowanceCharge[] zFLogisticsServiceCharges; private IZUGFeRDAllowanceCharge[] zFLogisticsServiceCharges;
private IZUGFeRDExportableItem[] zFItems; private IZUGFeRDExportableItem[] zFItems;
private IZUGFeRDExportableContact recipient; private IZUGFeRDExportableTradeParty recipient;
private IZUGFeRDTradeSettlementPayment[] settlementPayments; private IZUGFeRDTradeSettlementPayment[] settlementPayments;
private IZUGFeRDDate zfDeliveryDate;
private String ownTaxID; private String ownTaxID;
private String ownVATID; private String ownVATID;
private String ownOrganisationName; private String ownOrganisationName;
@@ -44,6 +43,7 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran
private String currency; private String currency;
private String paymentTermDescription; private String paymentTermDescription;
private String referenceNumber; private String referenceNumber;
private Profile profile;
@Override @Override
public String getNumber() { public String getNumber() {
@@ -86,15 +86,10 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran
} }
@Override @Override
public IZUGFeRDExportableContact getRecipient() { public IZUGFeRDExportableTradeParty getRecipient() {
return recipient; return recipient;
} }
@Override
public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
return settlementPayments;
}
@Override @Override
public String getOwnTaxID() { public String getOwnTaxID() {
return ownTaxID; return ownTaxID;
@@ -150,117 +145,107 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran
return referenceNumber; return referenceNumber;
} }
@Override public IExportableTransactionImpl setNumber(String number) {
public IZUGFeRDDate getZFDeliveryDate() {
return zfDeliveryDate;
}
public IZUGFeRDExportableTransactionImpl setNumber(String number) {
this.number = number; this.number = number;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setIssueDate(Date issueDate) { public IExportableTransactionImpl setIssueDate(Date issueDate) {
this.issueDate = issueDate; this.issueDate = issueDate;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setOwnOrganisationFullPlaintextInfo(String ownOrganisationFullPlaintextInfo) { public IExportableTransactionImpl setOwnOrganisationFullPlaintextInfo(String ownOrganisationFullPlaintextInfo) {
this.ownOrganisationFullPlaintextInfo = ownOrganisationFullPlaintextInfo; this.ownOrganisationFullPlaintextInfo = ownOrganisationFullPlaintextInfo;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setDueDate(Date dueDate) { public IExportableTransactionImpl setDueDate(Date dueDate) {
this.dueDate = dueDate; this.dueDate = dueDate;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setZFAllowances(IZUGFeRDAllowanceCharge... zFAllowances) { public IExportableTransactionImpl setZFAllowances(IZUGFeRDAllowanceCharge... zFAllowances) {
this.zFAllowances = zFAllowances; this.zFAllowances = zFAllowances;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setZFCharges(IZUGFeRDAllowanceCharge... zFCharges) { public IExportableTransactionImpl setZFCharges(IZUGFeRDAllowanceCharge... zFCharges) {
this.zFCharges = zFCharges; this.zFCharges = zFCharges;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setZFLogisticsServiceCharges(IZUGFeRDAllowanceCharge... zFLogisticsServiceCharges) { public IExportableTransactionImpl setZFLogisticsServiceCharges(IZUGFeRDAllowanceCharge... zFLogisticsServiceCharges) {
this.zFLogisticsServiceCharges = zFLogisticsServiceCharges; this.zFLogisticsServiceCharges = zFLogisticsServiceCharges;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setZFItems(IZUGFeRDExportableItem... zFItems) { public IExportableTransactionImpl setZFItems(IZUGFeRDExportableItem... zFItems) {
this.zFItems = zFItems; this.zFItems = zFItems;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setRecipient(IZUGFeRDExportableContact recipient) { public IExportableTransactionImpl setRecipient(IZUGFeRDExportableTradeParty recipient) {
this.recipient = recipient; this.recipient = recipient;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setOwnTaxID(String ownTaxID) { public IExportableTransactionImpl setOwnTaxID(String ownTaxID) {
this.ownTaxID = ownTaxID; this.ownTaxID = ownTaxID;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setOwnVATID(String ownVATID) { public IExportableTransactionImpl setOwnVATID(String ownVATID) {
this.ownVATID = ownVATID; this.ownVATID = ownVATID;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setOwnOrganisationName(String ownOrganisationName) { public IExportableTransactionImpl setOwnOrganisationName(String ownOrganisationName) {
this.ownOrganisationName = ownOrganisationName; this.ownOrganisationName = ownOrganisationName;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setOwnStreet(String ownStreet) { public IExportableTransactionImpl setOwnStreet(String ownStreet) {
this.ownStreet = ownStreet; this.ownStreet = ownStreet;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setOwnZIP(String ownZIP) { public IExportableTransactionImpl setOwnZIP(String ownZIP) {
this.ownZIP = ownZIP; this.ownZIP = ownZIP;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setOwnLocation(String ownLocation) { public IExportableTransactionImpl setOwnLocation(String ownLocation) {
this.ownLocation = ownLocation; this.ownLocation = ownLocation;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setOwnCountry(String ownCountry) { public IExportableTransactionImpl setOwnCountry(String ownCountry) {
this.ownCountry = ownCountry; this.ownCountry = ownCountry;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setDeliveryDate(Date deliveryDate) { public IExportableTransactionImpl setDeliveryDate(Date deliveryDate) {
this.deliveryDate = deliveryDate; this.deliveryDate = deliveryDate;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setZfDeliveryDate(IZUGFeRDDate zfDeliveryDate) { public IExportableTransactionImpl setCurrency(String currency) {
this.zfDeliveryDate = zfDeliveryDate;
return this;
}
public IZUGFeRDExportableTransactionImpl setCurrency(String currency) {
this.currency = currency; this.currency = currency;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setPaymentTermDescription(String paymentTermDescription) { public IExportableTransactionImpl setPaymentTermDescription(String paymentTermDescription) {
this.paymentTermDescription = paymentTermDescription; this.paymentTermDescription = paymentTermDescription;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setReferenceNumber(String referenceNumber) { public IExportableTransactionImpl setReferenceNumber(String referenceNumber) {
this.referenceNumber = referenceNumber; this.referenceNumber = referenceNumber;
return this; return this;
} }
public IZUGFeRDExportableTransactionImpl setTradeSettlementPayment(IZUGFeRDTradeSettlementPayment... settlementPayments) { public IExportableTransactionImpl setTradeSettlementPayment(IZUGFeRDTradeSettlementPayment... settlementPayments) {
this.settlementPayments = settlementPayments; this.settlementPayments = settlementPayments;
return this; return this;
} }

View File

@@ -24,9 +24,10 @@ public class IZUGFeRDAllowanceChargeImpl implements IZUGFeRDAllowanceCharge {
private BigDecimal totalAmount; private BigDecimal totalAmount;
private String reason; private String reason;
private BigDecimal taxPercent; private BigDecimal taxPercent;
boolean isCharge=true;
@Override @Override
public BigDecimal getTotalAmount() { public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) {
return totalAmount; return totalAmount;
} }
@@ -40,6 +41,16 @@ public class IZUGFeRDAllowanceChargeImpl implements IZUGFeRDAllowanceCharge {
return taxPercent; return taxPercent;
} }
@Override
public boolean isCharge() {
return isCharge;
}
public IZUGFeRDAllowanceChargeImpl setAllowance() {
isCharge = false;
return this;
}
public IZUGFeRDAllowanceChargeImpl setTotalAmount(BigDecimal totalAmount) { public IZUGFeRDAllowanceChargeImpl setTotalAmount(BigDecimal totalAmount) {
this.totalAmount = totalAmount; this.totalAmount = totalAmount;
return this; return this;

View File

@@ -1,30 +0,0 @@
package org.mustangproject.ZUGFeRD;
import java.util.Date;
public class IZUGFeRDDateImpl implements IZUGFeRDDate {
private Date date;
private ZUGFeRDDateFormat format = ZUGFeRDDateFormat.DATE;
public IZUGFeRDDateImpl setDate(Date date) {
this.date = date;
return this;
}
public IZUGFeRDDateImpl setFormat(ZUGFeRDDateFormat format) {
this.format = format;
return this;
}
@Override
public Date getDate() {
return date;
}
@Override
public ZUGFeRDDateFormat getFormat() {
return format;
}
}

View File

@@ -27,26 +27,11 @@ public class IZUGFeRDTradeSettlementPaymentImpl implements IZUGFeRDTradeSettleme
private String ownIBAN; private String ownIBAN;
private String ownPaymentInfoText; private String ownPaymentInfoText;
@Override
public String getOwnKto() {
return ownKto;
}
@Override
public String getOwnBLZ() {
return ownBLZ;
}
@Override @Override
public String getOwnBIC() { public String getOwnBIC() {
return ownBIC; return ownBIC;
} }
@Override
public String getOwnBankName() {
return ownBankName;
}
@Override @Override
public String getOwnIBAN() { public String getOwnIBAN() {
return ownIBAN; return ownIBAN;

View File

@@ -22,9 +22,7 @@ import junit.framework.TestCase;
import java.math.BigDecimal; import java.math.BigDecimal;
import org.mustangproject.ZUGFeRD.MustangReaderTestCase.Item; public abstract class MustangReaderTestCase extends TestCase implements IExportableTransaction {
public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRDExportableTransaction {
public MustangReaderTestCase(String testName) { public MustangReaderTestCase(String testName) {
super(testName); super(testName);
@@ -32,7 +30,7 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
@Override @Override
public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() { public IZUGFeRDTradeSettlement[] getTradeSettlement() {
Payment[] payments = new Payment[1]; Payment[] payments = new Payment[1];
payments[0] = new Payment(); payments[0] = new Payment();
return payments; return payments;
@@ -40,26 +38,11 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
protected class Payment implements IZUGFeRDTradeSettlementPayment { protected class Payment implements IZUGFeRDTradeSettlementPayment {
@Override
public String getOwnKto() {
return "44421800";
}
@Override
public String getOwnBLZ() {
return "41441604";
}
@Override @Override
public String getOwnBIC() { public String getOwnBIC() {
return "COBADEFFXXX"; return "COBADEFFXXX";
} }
@Override
public String getOwnBankName() {
return "Commerzbank";
}
@Override @Override
public String getOwnPaymentInfoText() { public String getOwnPaymentInfoText() {
return "Überweisung"; return "Überweisung";
@@ -71,7 +54,7 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
} }
} }
protected class RecipientContact implements IZUGFeRDExportableContact { protected class RecipientTradeParty implements IZUGFeRDExportableTradeParty {
@Override @Override
public String getCountry() { public String getCountry() {
@@ -125,6 +108,41 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
} }
protected class SenderTradeParty implements IZUGFeRDExportableTradeParty {
@Override
public String getName() {
return "Bei Spiel GmbH";
}
@Override
public String getZIP() {
return "12345";
}
@Override
public String getCountry() {
return "DE";
}
@Override
public String getLocation() {
return "Stadthausen";
}
@Override
public String getStreet() {
return "Ecke 12";
}
@Override
public String getTaxID() {
return "0815";
}
}
protected class Item implements IZUGFeRDExportableItem { protected class Item implements IZUGFeRDExportableItem {
public Item(BigDecimal price, BigDecimal quantity, IZUGFeRDExportableProduct product) { public Item(BigDecimal price, BigDecimal quantity, IZUGFeRDExportableProduct product) {

View File

@@ -31,13 +31,13 @@ import java.nio.charset.StandardCharsets;
@FixMethodOrder(MethodSorters.NAME_ASCENDING) @FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class MustangReaderWriterCustomXMLTest extends TestCase { public class MustangReaderWriterCustomXMLTest extends TestCase {
/** /**
* Create the test case * Create the test case
* *
* @param testName name of the test case * @param testName name of the test case
*/ */
public MustangReaderWriterCustomXMLTest(String testName) { public MustangReaderWriterCustomXMLTest(String testName) {
super(testName); super(testName);
} }
@@ -58,7 +58,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
try { try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf"); InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporter zea1 = new ZUGFeRDExporterFromA1Factory().setProducer("My Application").setCreator("Test").setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931) IZUGFeRDExporter zea1 = new ZUGFeRDExporterFromA1().setProducer("My Application").setCreator("Test").setProfile(Profiles.getByName("EN16931"))
.load(SOURCE_PDF); .load(SOURCE_PDF);
final byte[] UTF8ByteOrderMark = new byte[]{(byte) 0xef, (byte) 0xbb, (byte) 0xbf}; final byte[] UTF8ByteOrderMark = new byte[]{(byte) 0xef, (byte) 0xbb, (byte) 0xbf};
@@ -256,7 +256,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
" </ram:ApplicableHeaderTradeSettlement>\n" + " </ram:ApplicableHeaderTradeSettlement>\n" +
" </rsm:SupplyChainTradeTransaction>\n" + " </rsm:SupplyChainTradeTransaction>\n" +
"</rsm:CrossIndustryInvoice>"; "</rsm:CrossIndustryInvoice>";
zea1.setZUGFeRDXMLData(ownZUGFeRDXML.getBytes("UTF-8")); zea1.setXML(ownZUGFeRDXML.getBytes("UTF-8"));
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
zea1.disableAutoClose(true); zea1.disableAutoClose(true);
zea1.export(TARGET_PDF); zea1.export(TARGET_PDF);
@@ -297,11 +297,11 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
try { try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf"); InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporter zea1 = new ZUGFeRDExporterFromA1Factory() IZUGFeRDExporter zea1 = new ZUGFeRDExporterFromA1()
.setProducer("My Application") .setProducer("My Application")
.setCreator("Test") .setCreator("Test")
.setZUGFeRDVersion(1) .setZUGFeRDVersion(1)
.setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.BASIC) .setProfile(Profiles.getByName("BASIC",1))
.load(SOURCE_PDF); .load(SOURCE_PDF);
/* 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. */ /* 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 = "<rsm:CrossIndustryDocument xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12\" xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15\" xmlns:rsm=\"urn:ferd:CrossIndustryDocument:invoice:1p0\">\n" String ownZUGFeRDXML = "<rsm:CrossIndustryDocument xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12\" xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15\" xmlns:rsm=\"urn:ferd:CrossIndustryDocument:invoice:1p0\">\n"
@@ -437,7 +437,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
+ "<ram:Name>Heiße Luft pro Liter</ram:Name>\n" + "<ram:Description/>\n" + "<ram:Name>Heiße Luft pro Liter</ram:Name>\n" + "<ram:Description/>\n"
+ "</ram:SpecifiedTradeProduct>\n" + "</ram:IncludedSupplyChainTradeLineItem>\n" + "</ram:SpecifiedTradeProduct>\n" + "</ram:IncludedSupplyChainTradeLineItem>\n"
+ "</rsm:SpecifiedSupplyChainTradeTransaction>\n" + "</rsm:CrossIndustryDocument>"; + "</rsm:SpecifiedSupplyChainTradeTransaction>\n" + "</rsm:CrossIndustryDocument>";
zea1.setZUGFeRDXMLData(ownZUGFeRDXML.getBytes("UTF-8")); zea1.setXML(ownZUGFeRDXML.getBytes("UTF-8"));
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
zea1.disableAutoClose(true); zea1.disableAutoClose(true);

View File

@@ -76,8 +76,8 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
@Override @Override
public IZUGFeRDExportableContact getOwnContact() { public IZUGFeRDExportableTradeParty getSender() {
return new SenderContact(); return new SenderTradeParty();
} }
@@ -97,8 +97,8 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
} }
@Override @Override
public IZUGFeRDExportableContact getRecipient() { public IZUGFeRDExportableTradeParty getRecipient() {
return new RecipientContact(); return new RecipientTradeParty();
} }
@Override @Override
@@ -150,6 +150,7 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
return "AB321"; return "AB321";
} }
/** /**
* Create the test case * Create the test case
* *
@@ -180,8 +181,8 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
// Reading ZUGFeRD // Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04"); assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); assertEquals(zi.getBIC(), "COBADEFFXXX");
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00");
assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getDueDate(), "20170530"); assertEquals(zi.getDueDate(), "20170530");
assertEquals(zi.getForeignReference(), getNumber()); assertEquals(zi.getForeignReference(), getNumber());
@@ -202,18 +203,18 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
try (InputStream SOURCE_PDF = try (InputStream SOURCE_PDF =
this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf"); this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
) {
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory() ZUGFeRDExporterFromA3 ze = new ZUGFeRDExporterFromA3()
.setProducer("My Application") .setProducer("My Application")
.setCreator(System.getProperty("user.name")) .setCreator(System.getProperty("user.name"))
.setZUGFeRDVersion(1) .setZUGFeRDVersion(1)
.ignorePDFAErrors() .load(SOURCE_PDF);
.load(SOURCE_PDF)) { ze.setTransaction(this);
ze.PDFattachZugferdFile(this);
String theXML = new String(ze.getProvider().getXML()); String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryDocument")); assertTrue(theXML.contains("<rsm:CrossIndustryDocument"));
ze.export(TARGET_PDF); ze.export(TARGET_PDF);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace();
fail("IOException should not happen in testEdgeExport "); fail("IOException should not happen in testEdgeExport ");
} }
@@ -222,8 +223,8 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
// Reading ZUGFeRD // Reading ZUGFeRD
assertEquals("571.04", zi.getAmount()); assertEquals("571.04", zi.getAmount());
assertEquals(getTradeSettlementPayment()[0].getOwnBIC(), zi.getBIC()); assertEquals("COBADEFFXXX", zi.getBIC());
assertEquals(getTradeSettlementPayment()[0].getOwnIBAN(), zi.getIBAN()); assertEquals("DE88 2008 0000 0970 3757 00", zi.getIBAN());
assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber()); assertEquals(zi.getForeignReference(), getNumber());
try { try {

View File

@@ -100,13 +100,13 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
} }
@Override @Override
public IZUGFeRDExportableContact getRecipient() { public IZUGFeRDExportableTradeParty getRecipient() {
return new RecipientContact(); return new RecipientTradeParty();
} }
@Override @Override
public IZUGFeRDExportableContact getOwnContact() { public IZUGFeRDExportableTradeParty getSender() {
return new SenderContact(); return new SenderTradeParty();
} }
@Override @Override
@@ -196,8 +196,8 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
// Reading ZUGFeRD // Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04"); assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); assertEquals(zi.getBIC(), "COBADEFFXXX");
assertEquals(zi.getIBAN(),getTradeSettlementPayment()[0].getOwnIBAN()); assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00");
assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), "RE-20170509/505"); assertEquals(zi.getForeignReference(), "RE-20170509/505");
assertEquals(zi.getBankName(), "Commerzbank"); assertEquals(zi.getBankName(), "Commerzbank");
@@ -304,7 +304,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf"); .getResourceAsStream("/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setAttachZUGFeRDHeaders(false).load(SOURCE_PDF); IZUGFeRDExporter ze = new ZUGFeRDExporterFromA1().setAttachZUGFeRDHeaders(false).load(SOURCE_PDF);
File tempFile = File.createTempFile("ZUGFeRD-", "-test"); File tempFile = File.createTempFile("ZUGFeRD-", "-test");
ze.export(tempFile.getAbsolutePath()); ze.export(tempFile.getAbsolutePath());
@@ -317,7 +317,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
InputStream SOURCE_PDF = this.getClass() InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf"); .getResourceAsStream("/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setAttachZUGFeRDHeaders(false).load(SOURCE_PDF); IZUGFeRDExporter ze = new ZUGFeRDExporterFromA1().setAttachZUGFeRDHeaders(false).load(SOURCE_PDF);
File tempFile = File.createTempFile("ZUGFeRD-", "-test"); File tempFile = File.createTempFile("ZUGFeRD-", "-test");
tempFile.deleteOnExit(); tempFile.deleteOnExit();
@@ -358,9 +358,9 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
try (InputStream SOURCE_PDF = this.getClass() 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)) { IZUGFeRDExporter ze = new ZUGFeRDExporterFromA1().setZUGFeRDVersion(2).setProfile(Profiles.getByName("EN16931")).load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this); ze.setTransaction(this);
ze.disableAutoClose(true); ze.disableAutoClose(true);
ze.export(TARGET_PDF); ze.export(TARGET_PDF);
@@ -383,9 +383,9 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
// Reading ZUGFeRD // Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04"); assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); assertEquals(zi.getBIC(), "COBADEFFXXX");
assertEquals(zi.getReference(), getReferenceNumber()); assertEquals(zi.getReference(), getReferenceNumber());
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00");
assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber()); assertEquals(zi.getForeignReference(), getNumber());
} }
@@ -402,9 +402,9 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
try (InputStream SOURCE_PDF = this.getClass() try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf"); .getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(1).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.COMFORT).load(SOURCE_PDF)) { IZUGFeRDExporter ze = new ZUGFeRDExporterFromA1().setZUGFeRDVersion(1).setProfile(Profiles.getByName("COMFORT",1)).load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this); ze.setTransaction(this);
ze.disableAutoClose(true); ze.disableAutoClose(true);
ze.export(TARGET_PDF); ze.export(TARGET_PDF);
@@ -430,9 +430,17 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
try (InputStream SOURCE_PDF = this.getClass() try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf"); .getResourceAsStream("/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) { ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setZUGFeRDVersion(2).setProfile(Profiles.getByName("EN16931")).load(SOURCE_PDF)) {
ze.setFacturX(); ByteArrayOutputStream result = new ByteArrayOutputStream();
ze.PDFattachZugferdFile(this); byte[] buffer = new byte[1024];
int length;
while ((length = SOURCE_PDF.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
ze.addAdditionalFile("test.pdf", result.toByteArray());
ze.setTransaction(this);
ze.disableAutoClose(true); ze.disableAutoClose(true);
ze.export(TARGET_PDF); ze.export(TARGET_PDF);
@@ -451,11 +459,11 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF); ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
// Reading ZUGFeRD // Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04"); assertEquals("571.04", zi.getAmount());
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); assertEquals("COBADEFFXXX", zi.getBIC());
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); assertEquals("DE88 2008 0000 0970 3757 00", zi.getIBAN());
assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(getOwnOrganisationName(), zi.getHolder());
assertEquals(zi.getForeignReference(), getNumber()); assertEquals(getNumber(), zi.getForeignReference());
} }
public void testExceptionOnPDF14() { public void testExceptionOnPDF14() {
@@ -467,9 +475,9 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
try (InputStream SOURCE_PDF = this.getClass() try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDF14.pdf"); .getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDF14.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().load(SOURCE_PDF)) { IZUGFeRDExporter ze = new ZUGFeRDExporterFromA1().load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this); ze.setTransaction(this);
ze.export(TARGET_PDF); ze.export(TARGET_PDF);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();

View File

@@ -0,0 +1,118 @@
/** **********************************************************************
*
* 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.TestCase;
import junit.framework.TestSuite;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import org.mustangproject.Contact;
import org.mustangproject.Invoice;
import org.mustangproject.Item;
import org.mustangproject.Product;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class UXTest extends TestCase {
final String TARGET_PDF = "./target/testout-UX.pdf";
public void testShortExport() {
// the writing part
/*
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf"))
{
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setOwnOrganisationName("My company").setOwnStreet("teststr").setOwnZIP("12345").setOwnLocation("teststadt").setOwnCountry("DE").setOwnTaxID("4711").setOwnVATID("0815").setRecipient(new Contact("Franz Müller", "0177123456", "fmueller@test.com", "teststr.12", "55232", "Entenhausen", "DE")).setNumber("INV/123").addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(0)), new BigDecimal(1.0), new BigDecimal(1.0)));
new ZUGFeRDExporterFromA1().load("source.pdf").setTransaction(i).export(TARGET_PDF);
} catch (Exception e) {
fail("Exception should not be raised in testEdgeExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
assertTrue(zi.getUTF8().contains("<ram:DueDateDateTime>"));
// Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getInvoiceID(), "RE-20170509/505");
assertEquals(zi.getZUGFeRDProfil(), "COMFORT");
assertEquals(zi.getInvoiceCurrencyCode(), "EUR");
assertEquals(zi.getIssuerAssignedID(),"");
assertEquals(zi.getIssueDate(), "20170509");
assertEquals(zi.getTaxPointDate(), "20170507");
assertEquals(zi.getPaymentTerms(), "Zahlbar ohne Abzug bis zum 30.05.2017");
assertEquals(zi.getLineTotalAmount(), "496.00");
assertEquals(zi.getTaxBasisTotalAmount(), "496.00");
assertEquals(zi.getTaxTotalAmount(),"75.04");
assertEquals(zi.getRoundingAmount(), "");
assertEquals(zi.getPaidAmount(), "0.00");
assertEquals(zi.getBuyerTradePartyName(), "Theodor Est");
assertEquals(zi.getBuyerTradePartyGlobalID(), "");
assertEquals(zi.getSellerTradePartyGlobalID(), "");
assertEquals(zi.getBuyerTradePartyID(), "DE999999999");
assertEquals(zi.getBuyertradePartySpecifiedTaxRegistrationID(), "DE999999999");
assertEquals(zi.getIncludedNote(), "");
assertEquals(zi.getDocumentCode(),"380");
assertEquals(zi.getReference(),"AB321");
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBuyerTradePartyAddress().getPostcodeCode(), "88802");
assertEquals(zi.getBuyerTradePartyAddress().getLineOne(), "Bahnstr. 42");
assertEquals(zi.getBuyerTradePartyAddress().getLineTwo(), null);
assertEquals(zi.getBuyerTradePartyAddress().getLineThree(), null);
assertEquals(zi.getBuyerTradePartyAddress().getCountrySubDivisionName(), null);
assertEquals(zi.getBuyerTradePartyAddress().getCountryID(), "DE");
assertEquals(zi.getBuyerTradePartyAddress().getCityName(), "Spielkreis");
assertEquals(zi.getSellerTradePartyAddress().getPostcodeCode(), "12345");
assertEquals(zi.getSellerTradePartyAddress().getLineOne(), "Ecke 12");
assertEquals(zi.getSellerTradePartyAddress().getLineTwo(), null);
assertEquals(zi.getSellerTradePartyAddress().getLineThree(), null);
assertEquals(zi.getSellerTradePartyAddress().getCountrySubDivisionName(), null);
assertEquals(zi.getSellerTradePartyAddress().getCountryID(), "DE");
assertEquals(zi.getSellerTradePartyAddress().getCityName(), "Stadthausen");
List<org.mustangproject.Item> li = zi.getLineItemList();
assertEquals(zi.getLineItemList().get(0).getId().toString(), "1");
assertEquals(zi.getLineItemList().get(0).getProduct().getBuyerAssignedID(), "");
assertEquals(zi.getLineItemList().get(0).getProduct().getSellerAssignedID(), "");
assertEquals(zi.getLineItemList().get(0).getLineTotalAmount().toString(), "160.00");
assertEquals(zi.getLineItemList().get(0).getQuantity().toString(), "1.0000");
assertEquals(zi.getLineItemList().get(0).getGrossPrice().toString(), "160.0000");
assertEquals(zi.getLineItemList().get(0).getProduct().getVATPercent().toString(), "7.00");
assertEquals(zi.getLineItemList().get(0).getProduct().getName(), "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung");
assertEquals(zi.getLineItemList().get(0).getProduct().getDescription(), "");
try {
assertEquals(zi.getVersion(), 2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
}
}

View File

@@ -0,0 +1,67 @@
/**
* *********************************************************************
* <p>
* Copyright 2019 Jochen Staerk
* <p>
* Use is subject to license terms.
* <p>
* 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.
* <p>
* 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.
* <p>
* See the License for the specific language governing permissions and
* limitations under the License.
* <p>
* **********************************************************************
*/
package org.mustangproject.ZUGFeRD;
import junit.framework.TestCase;
import org.mustangproject.*;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import org.mustangproject.ZUGFeRD.ZUGFeRD2PullProvider;
import java.math.BigDecimal;
import java.util.Date;
import static org.xmlunit.assertj.XmlAssert.assertThat;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class XRTest extends TestCase {
public void testPushExport() {
// the writing part
String orgname = "Test company";
String number = "123";
String amountStr = "1.00";
BigDecimal amount = new BigDecimal(amountStr);
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname,"teststr","55232","teststadt","DE")).setOwnTaxID("4711").setOwnVATID("0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(0)), amount, new BigDecimal(1.0)));
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
zf2p.generateXML(i);
String theXML = new String(zf2p.getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
assertThat(theXML).valueByXPath("count(//*[local-name()='IncludedSupplyChainTradeLineItem'])")
.asInt()
.isEqualTo(1); //2 errors are OK because there is a known bug
assertThat(theXML).valueByXPath("//*[local-name()='DuePayableAmount']")
.asDouble()
.isEqualTo(1);
}
}

View File

@@ -30,13 +30,12 @@ import java.util.GregorianCalendar;
import org.junit.FixMethodOrder; import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters; import org.junit.runners.MethodSorters;
import org.mustangproject.ZUGFeRD.MustangReaderTestCase.Item;
import junit.framework.Test; import junit.framework.Test;
import junit.framework.TestSuite; import junit.framework.TestSuite;
@FixMethodOrder(MethodSorters.NAME_ASCENDING) @FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ZF2EdgeTest extends MustangReaderTestCase implements IZUGFeRDExportableTransaction { public class ZF2EdgeTest extends MustangReaderTestCase implements IExportableTransaction {
final String TARGET_PDF = "./target/testout-ZF2newEdge.pdf"; final String TARGET_PDF = "./target/testout-ZF2newEdge.pdf";
protected class EdgeProduct implements IZUGFeRDExportableProduct { protected class EdgeProduct implements IZUGFeRDExportableProduct {
@@ -101,11 +100,6 @@ public class ZF2EdgeTest extends MustangReaderTestCase implements IZUGFeRDExport
} }
@Override
public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
return null;
}
@Override @Override
public IZUGFeRDTradeSettlement[] getTradeSettlement() { public IZUGFeRDTradeSettlement[] getTradeSettlement() {
IZUGFeRDTradeSettlement[] payments = new DebitPayment[1]; IZUGFeRDTradeSettlement[] payments = new DebitPayment[1];
@@ -154,8 +148,8 @@ public class ZF2EdgeTest extends MustangReaderTestCase implements IZUGFeRDExport
} }
@Override @Override
public IZUGFeRDExportableContact getOwnContact() { public IZUGFeRDExportableTradeParty getSender() {
return new SenderContact(); return new SenderTradeParty();
} }
@Override @Override
@@ -174,13 +168,13 @@ public class ZF2EdgeTest extends MustangReaderTestCase implements IZUGFeRDExport
} }
@Override @Override
public IZUGFeRDExportableContact getRecipient() { public IZUGFeRDExportableTradeParty getRecipient() {
return new RecipientContact(); return new RecipientTradeParty();
} }
@Override @Override
public IZUGFeRDExportableContact getDeliveryAddress() { public IZUGFeRDExportableTradeParty getDeliveryAddress() {
return new RecipientContact(); return new RecipientTradeParty();
} }
@Override @Override
@@ -266,12 +260,12 @@ public class ZF2EdgeTest extends MustangReaderTestCase implements IZUGFeRDExport
// the writing part // the writing part
try (InputStream SOURCE_PDF = this.getClass() try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf"); .getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application") ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors() .setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) { .load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this); ze.setTransaction(this);
String theXML = new String(ze.getProvider().getXML()); String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice")); assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_PDF); ze.export(TARGET_PDF);
@@ -316,10 +310,10 @@ public class ZF2EdgeTest extends MustangReaderTestCase implements IZUGFeRDExport
try (InputStream SOURCE_PDF = this.getClass() try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf"); .getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application") IZUGFeRDExporter ze = new ZUGFeRDExporterFromA3().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors() .setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).disableFacturX()
.load(SOURCE_PDF)) { .load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this); ze.setTransaction(this);
String theXML = new String(ze.getProvider().getXML()); String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice")); assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(bos); ze.export(bos);

View File

@@ -1,45 +1,48 @@
/** ********************************************************************** /**
* * *********************************************************************
* <p>
* Copyright 2019 Jochen Staerk * Copyright 2019 Jochen Staerk
* * <p>
* Use is subject to license terms. * Use is subject to license terms.
* * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * 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. * of the License at http://www.apache.org/licenses/LICENSE-2.0.
* * <p>
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * <p>
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* * <p>
*********************************************************************** */ * **********************************************************************
*/
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar;
import org.mustangproject.*;
import org.junit.FixMethodOrder; import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters; import org.junit.runners.MethodSorters;
import junit.framework.TestCase; import junit.framework.TestCase;
import junit.framework.Test;
import junit.framework.TestSuite;
@FixMethodOrder(MethodSorters.NAME_ASCENDING) @FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ZF2PushTest extends TestCase { public class ZF2PushTest extends TestCase {
final String TARGET_PDF = "./target/testout-ZF2Push.pdf"; final String TARGET_PDF = "./target/testout-ZF2Push.pdf";
final String TARGET_CORRECTIONPDF = "./target/testout-ZF2PushCorrection.pdf";
final String TARGET_ITEMCHARGESALLOWANCESPDF = "./target/testout-ZF2PushItemChargesAllowances.pdf";
final String TARGET_CHARGESALLOWANCESPDF = "./target/testout-ZF2PushChargesAllowances.pdf";
final String TARGET_RELATIVECHARGESALLOWANCESPDF = "./target/testout-ZF2PushRelativeChargesAllowances.pdf";
final String TARGET_ATTACHMENTSPDF = "./target/testout-ZF2PushAttachments.pdf";
public void testPushExport() { public void testPushExport() {
@@ -49,16 +52,22 @@ public class ZF2PushTest extends TestCase {
String number = "123"; String number = "123";
String amountStr = "1.00"; String amountStr = "1.00";
BigDecimal amount = new BigDecimal(amountStr); BigDecimal amount = new BigDecimal(amountStr);
String occurenceFrom = "20201001";
String occurenceTo = "20201005";
String contractID = "376zreurzu0983";
try (InputStream SOURCE_PDF = this.getClass() try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf"); .getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application") ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors() .setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) { .load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(new ZUGFeRD2PushProvider().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setOwnOrganisationName(orgname).setOwnStreet("teststr").setOwnZIP("55232").setOwnLocation("teststadt").setOwnCountry("DE").setOwnTaxID("4711").setOwnVATID("0815").setRecipient(new Contact("Franz Müller", "0177123456", "fmueller@test.com", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number).addItem(new Item(new Product("Testprodukt","","C62",new BigDecimal(0)),amount,new BigDecimal(1.0)))); try {
String theXML = new String(ze.getProvider().getXML()); ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setContractReferencedDocument(contractID).setOccurrencePeriod(new SimpleDateFormat("yyyyMMdd").parse(occurenceFrom), new SimpleDateFormat("yyyyMMdd").parse(occurenceTo)).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addBankDetails(new BankDetails("777666555", "DE4321"))).setOwnTaxID("4711").setOwnVATID("DE19990815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setAdditionalAddress("Hinterhaus 3").setContact(new Contact("nameRep", "phoneRep", "emailRep@test.com"))).setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0))));
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice")); } catch (ParseException ex) {
throw new RuntimeException("Parse exception");
}
ze.export(TARGET_PDF); ze.export(TARGET_PDF);
} catch (IOException e) { } catch (IOException e) {
fail("IOException should not be raised in testEdgeExport"); fail("IOException should not be raised in testEdgeExport");
@@ -66,11 +75,19 @@ public class ZF2PushTest extends TestCase {
// now check the contents (like MustangReaderTest) // now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF); ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
assertTrue(zi.getUTF8().contains("777666555")); //the iban
assertFalse(zi.getUTF8().contains("EUR")); assertTrue(zi.getUTF8().contains("<rsm:CrossIndustryInvoice"));
assertTrue(zi.getUTF8().contains("EUR")); //default invoice currency
assertTrue(zi.getUTF8().contains(occurenceFrom));
assertTrue(zi.getUTF8().contains(occurenceTo));
assertTrue(zi.getUTF8().contains(contractID));
assertTrue(zi.getUTF8().contains("Hinterhaus")); // lineTwo/additionalAddress
assertTrue(zi.getUTF8().contains("0815"));
// Reading ZUGFeRD // Reading ZUGFeRD
assertEquals(amountStr, zi.getAmount()); assertEquals("1.19", zi.getAmount());
assertEquals(zi.getHolder(), orgname); assertEquals(zi.getHolder(), orgname);
assertEquals(zi.getForeignReference(), number); assertEquals(zi.getForeignReference(), number);
try { try {
@@ -81,4 +98,237 @@ public class ZF2PushTest extends TestCase {
} }
public void testAttachmentsExport() {
String orgname = "Test company";
String number = "123";
String amountStr = "1.00";
String taxID = "9990815";
BigDecimal amount = new BigDecimal(amountStr);
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) {
byte[] b = {12, 13};
ze.attachFile("one.pdf", b, "Application/PDF", "Alternative");
ze.attachFile("two.pdf", b, "Application/PDF", "Alternative");
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID(taxID)).setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE"))).setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_ATTACHMENTSPDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_ATTACHMENTSPDF);
assertTrue(zi.getUTF8().contains("EUR"));
assertTrue(zi.getUTF8().contains(taxID));
// Reading ZUGFeRD
assertEquals("1.19", zi.getAmount());
assertEquals(zi.getHolder(), orgname);
assertEquals(zi.getForeignReference(), number);
try {
assertEquals(zi.getVersion(), 2);
} catch (Exception e) {
e.printStackTrace();
}
}
public void testItemChargesAllowancesExport() {
String orgname = "Test company";
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("extended").ignorePDFAErrors()
.load(SOURCE_PDF)) {
// ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname,"teststr", "55232","teststadt","DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number)
// .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setContact(new Contact("contact testname","123456","contact.testemail@example.org" ).setFax("0911623562"))).setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1"))))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50))))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1))))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1))).addAllowance(new Allowance(new BigDecimal("1"))))
);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_ITEMCHARGESALLOWANCESPDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_ITEMCHARGESALLOWANCESPDF);
assertTrue(zi.getUTF8().contains("EUR"));
assertTrue(zi.getUTF8().contains("0911623562")); // fax number
// Reading ZUGFeRD
assertEquals("18.33", zi.getAmount());
assertEquals(zi.getHolder(), orgname);
assertEquals(zi.getForeignReference(), number);
try {
assertEquals(zi.getVersion(), 2);
} catch (Exception e) {
e.printStackTrace();
}
}
public void testChargesAllowancesExport() {
String orgname = "Test company";
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile(Profiles.getByName("en16931")).ignorePDFAErrors()
.load(SOURCE_PDF)) {
ze.setTransaction(new Invoice().setCurrency("CHF").setDueDate(new Date()).setOccurrenceDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
.addCharge(new Charge(new BigDecimal(0.5)).setTaxPercent(new BigDecimal(19)))
.addAllowance(new Allowance(new BigDecimal(0.2)).setTaxPercent(new BigDecimal(19)))
);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_CHARGESALLOWANCESPDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_CHARGESALLOWANCESPDF);
assertFalse(zi.getUTF8().contains("EUR"));
// Reading ZUGFeRD
assertEquals("11.07", zi.getAmount());
assertEquals(zi.getHolder(), orgname);
assertEquals(zi.getForeignReference(), number);
try {
assertEquals(zi.getVersion(), 2);
} catch (Exception e) {
e.printStackTrace();
}
}
public void testRelativeChargesAllowancesExport() {
String orgname = "Test company";
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile(Profiles.getByName("extended")).ignorePDFAErrors()
.load(SOURCE_PDF)) {
ze.setTransaction(new Invoice().setCurrency("CHF").setDueDate(new Date()).setOccurrenceDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19))))
.addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)))
);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_RELATIVECHARGESALLOWANCESPDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_RELATIVECHARGESALLOWANCESPDF);
assertFalse(zi.getUTF8().contains("EUR"));
// Reading ZUGFeRD
assertEquals("6.25", zi.getAmount());
assertEquals(zi.getHolder(), orgname);
assertEquals(zi.getForeignReference(), number);
try {
assertEquals(zi.getVersion(), 2);
} catch (Exception e) {
e.printStackTrace();
}
}
public void testCorrectionExport() {
String orgname = "Test company";
String number = "123";
String priceStr = "1.00";
BigDecimal price = new BigDecimal(priceStr);
BigDecimal amount = new BigDecimal(-1.0);
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) {
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setOccurrencePeriod(new Date(), new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815")).setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0815")).setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, amount))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, amount))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, amount)).setCorrection("0815");
ze.setTransaction(i);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_CORRECTIONPDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_CORRECTIONPDF);
assertTrue(zi.getUTF8().contains("EUR"));
//totest: typecode 384, BuyerOrderReferencedDocument
// Reading ZUGFeRD
assertEquals("-3.57", zi.getAmount());
assertEquals(zi.getHolder(), orgname);
assertEquals(zi.getForeignReference(), number);
try {
assertEquals(zi.getVersion(), 2);
} catch (Exception e) {
e.printStackTrace();
}
}
} }

View File

@@ -24,7 +24,6 @@ import junit.framework.TestSuite;
import org.junit.FixMethodOrder; import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters; import org.junit.runners.MethodSorters;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -60,28 +59,8 @@ public class ZF2Test extends MustangReaderTestCase {
} }
@Override @Override
public String getOwnCountry() { public IZUGFeRDExportableTradeParty getSender() {
return "DE"; return new SenderTradeParty();
}
@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();
} }
@@ -101,8 +80,8 @@ public class ZF2Test extends MustangReaderTestCase {
} }
@Override @Override
public IZUGFeRDExportableContact getRecipient() { public IZUGFeRDExportableTradeParty getRecipient() {
return new RecipientContact(); return new RecipientTradeParty();
} }
@Override @Override
@@ -188,11 +167,11 @@ public class ZF2Test extends MustangReaderTestCase {
try (InputStream SOURCE_PDF = this.getClass() try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf"); .getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application") ZUGFeRDExporterFromA3 ze = new ZUGFeRDExporterFromA3().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).ignorePDFAErrors() .setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("EN16931")
.load(SOURCE_PDF)) { .load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this); ze.setTransaction(this);
String theXML = new String(ze.getProvider().getXML()); String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice")); assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_PDF); ze.export(TARGET_PDF);
@@ -207,14 +186,39 @@ public class ZF2Test extends MustangReaderTestCase {
// Reading ZUGFeRD // Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04"); assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getInvoiceID(), "RE-20170509/505");
assertEquals(zi.getZUGFeRDProfil(), "COMFORT");
assertEquals(zi.getInvoiceCurrencyCode(), "EUR");
assertEquals(zi.getIssuerAssignedID(),"");
assertEquals(zi.getIssueDate(), "20170509");
assertEquals(zi.getTaxPointDate(), "20170507");
assertEquals(zi.getPaymentTerms(), "Zahlbar ohne Abzug bis zum 30.05.2017");
assertEquals(zi.getLineTotalAmount(), "496.00");
assertEquals(zi.getTaxBasisTotalAmount(), "496.00");
assertEquals(zi.getTaxTotalAmount(),"75.04");
assertEquals(zi.getRoundingAmount(), "");
assertEquals(zi.getPaidAmount(), "0.00");
assertEquals(zi.getBuyerTradePartyName(), "Theodor Est");
assertEquals(zi.getBuyerTradePartyGlobalID(), "");
assertEquals(zi.getSellerTradePartyGlobalID(), "");
assertEquals(zi.getBuyerTradePartyID(), "DE999999999");
assertEquals(zi.getBuyertradePartySpecifiedTaxRegistrationID(), "DE999999999");
assertEquals(zi.getIncludedNote(), "");
assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getDocumentCode(),"380"); assertEquals(zi.getDocumentCode(),"380");
assertEquals(zi.getReference(),"AB321"); assertEquals(zi.getReference(),"AB321");
assertEquals(zi.getAmount(), "571.04"); assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); assertEquals(zi.getBIC(), "COBADEFFXXX");
assertEquals(zi.getIBAN(),getTradeSettlementPayment()[0].getOwnIBAN()); assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00");
assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber()); assertEquals(zi.getForeignReference(), getNumber());
assertEquals(zi.getBuyerTradePartyAddress().getPostcodeCode(), "88802");
assertEquals(zi.getBuyerTradePartyAddress().getLineOne(), "Bahnstr. 42");
assertEquals(zi.getBuyerTradePartyAddress().getLineTwo(), null);
assertEquals(zi.getBuyerTradePartyAddress().getLineThree(), null);
assertEquals(zi.getBuyerTradePartyAddress().getCountrySubDivisionName(), null);
assertEquals(zi.getBuyerTradePartyAddress().getCountryID(), "DE");
assertEquals(zi.getBuyerTradePartyAddress().getCityName(), "Spielkreis");
assertEquals(zi.getSellerTradePartyAddress().getPostcodeCode(), "12345"); assertEquals(zi.getSellerTradePartyAddress().getPostcodeCode(), "12345");
assertEquals(zi.getSellerTradePartyAddress().getLineOne(), "Ecke 12"); assertEquals(zi.getSellerTradePartyAddress().getLineOne(), "Ecke 12");
assertEquals(zi.getSellerTradePartyAddress().getLineTwo(), null); assertEquals(zi.getSellerTradePartyAddress().getLineTwo(), null);
@@ -223,16 +227,16 @@ public class ZF2Test extends MustangReaderTestCase {
assertEquals(zi.getSellerTradePartyAddress().getCountryID(), "DE"); assertEquals(zi.getSellerTradePartyAddress().getCountryID(), "DE");
assertEquals(zi.getSellerTradePartyAddress().getCityName(), "Stadthausen"); assertEquals(zi.getSellerTradePartyAddress().getCityName(), "Stadthausen");
List<org.mustangproject.ZUGFeRD.Item> li = zi.getLineItemList(); List<org.mustangproject.Item> li = zi.getLineItemList();
assertEquals(zi.getLineItemList().get(0).getId().toString(), "1"); assertEquals(zi.getLineItemList().get(0).getId().toString(), "1");
assertEquals(zi.getLineItemList().get(0).product.getBuyerAssignedID(), ""); assertEquals(zi.getLineItemList().get(0).getProduct().getBuyerAssignedID(), "");
assertEquals(zi.getLineItemList().get(0).product.getSellerAssignedID(), ""); assertEquals(zi.getLineItemList().get(0).getProduct().getSellerAssignedID(), "");
assertEquals(zi.getLineItemList().get(0).getLineTotalAmount().toString(), "160.00"); assertEquals(zi.getLineItemList().get(0).getLineTotalAmount().toString(), "160.00");
assertEquals(zi.getLineItemList().get(0).getQuantity().toString(), "1.0000"); assertEquals(zi.getLineItemList().get(0).getQuantity().toString(), "1.0000");
assertEquals(zi.getLineItemList().get(0).getGrossPrice().toString(), "160.0000"); assertEquals(zi.getLineItemList().get(0).getGrossPrice().toString(), "160.0000");
assertEquals(zi.getLineItemList().get(0).product.getVATPercent().toString(), "7.00"); assertEquals(zi.getLineItemList().get(0).getProduct().getVATPercent().toString(), "7.00");
assertEquals(zi.getLineItemList().get(0).product.getName(), "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung"); assertEquals(zi.getLineItemList().get(0).getProduct().getName(), "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung");
assertEquals(zi.getLineItemList().get(0).product.getDescription(), ""); assertEquals(zi.getLineItemList().get(0).getProduct().getDescription(), "");
try { try {
assertEquals(zi.getVersion(), 2); assertEquals(zi.getVersion(), 2);

View File

@@ -19,15 +19,7 @@
*********************************************************************** */ *********************************************************************** */
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import java.io.ByteArrayOutputStream; import org.mustangproject.Invoice;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.junit.FixMethodOrder; import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters; import org.junit.runners.MethodSorters;
@@ -47,12 +39,17 @@ public class ZF2ZInvoiceImporterTest extends TestCase {
ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter(TARGET_PDF); ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter(TARGET_PDF);
Invoice invoice=zii.extractInvoice();
// Reading ZUGFeRD // Reading ZUGFeRD
assertEquals("Bei Spiel GmbH", zii.extractInvoice().getOwnOrganisationName()); assertEquals("Bei Spiel GmbH", invoice.getOwnOrganisationName());
assertEquals(3, zii.extractInvoice().getZFItems().length); assertEquals(3, invoice.getZFItems().length);
assertEquals("160.0000", zii.extractInvoice().getZFItems()[0].getPrice().toString()); assertEquals("400.0000", invoice.getZFItems()[1].getQuantity().toString());
/* assertEquals("160.0000", invoice.getZFItems()[0].getPrice().toString());
assertEquals("Heiße Luft pro Liter", invoice.getZFItems()[2].getProduct().getName());
assertEquals("7", invoice.getZFItems()[0].getProduct().getVATPercent().toString());
*/
} }

161
pom.xml
View File

@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?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" <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">
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> <modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId> <groupId>org.mustangproject</groupId>
<artifactId>core</artifactId> <artifactId>core</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>2.0.0-alpha4-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Mustang</name> <name>Mustang</name>
@@ -18,11 +17,117 @@
</description> </description>
<url>http://www.mustangproject.org/</url> <url>http://www.mustangproject.org/</url>
<scm> <scm>
<connection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</connection> <connection>scm:git:git://github.com/dexecutor/dependent-tasks-executor.git</connection>
<developerConnection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</developerConnection> <developerConnection>scm:git:git@github.com:dexecutor/dexecutor.git</developerConnection>
<url>https://github.com/ZUGFeRD/mustangproject</url> <url>https://github.com/dexecutor/dependent-tasks-executor</url>
<tag>mustang-1.7.3</tag> <tag>HEAD</tag>
</scm> </scm>
<build>
<pluginManagement>
<plugins>
<plugin><!-- mvn help:effective-pom will otherwise tell it just defaults
to 2.3.2 - which does not release in the maven repo, and neither shows any
error message :-( -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<localCheckout>true</localCheckout>
<pushChanges>false</pushChanges>
<mavenExecutorId>forked-path</mavenExecutorId>
<arguments>-Dgpg.passphrase=${gpg.passphrase}</arguments>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-provider-gitexe</artifactId>
<version>1.9.5</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<excludePackageNames>org.mustangproject.ZUGFeRD.model.*</excludePackageNames>
</configuration>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.0.0-M1</version>
<configuration>
<altDeploymentRepository>internal.repo::default::file://${project.build.directory}/mvn-repo
</altDeploymentRepository>
</configuration>
</plugin>
<!--<plugin>
<groupId>com.github.github</groupId>
<artifactId>site-maven-plugin</artifactId>
<version>0.12</version>
<configuration>
<message>Maven artifacts for ${project.version}</message>
- git commit message -
<noJekyll>true</noJekyll>
- disable webpage processing -
<outputDirectory>${project.build.directory}/mvn-repo</outputDirectory>
- matches distribution management repository url above -
<branch>refs/heads/mvn-repo</branch>
- remote branch name -
<includes>
<include>**/*</include>
</includes>
<merge>true</merge>
<repositoryName>mustangproject</repositoryName>
- github repo name -
<repositoryOwner>ZUGFeRD</repositoryOwner>
- github username -
</configuration>
<executions>
- run site-maven-plugin's 'site' target as part of the build's normal
'deploy' phase -
<execution>
<goals>
<goal>site</goal>
</goals>
<phase>deploy</phase>
</execution>
</executions>
</plugin>-->
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>attach-javadoc</id>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories> <repositories>
<repository><!-- for jargs --> <repository><!-- for jargs -->
<id>sonatype-oss-public</id> <id>sonatype-oss-public</id>
@@ -36,10 +141,13 @@
</repository> </repository>
</repositories> </repositories>
<distributionManagement> <distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository> <repository>
<id>internal.repo</id> <id>ossrh</id>
<name>Temporary Staging Repository</name> <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
<url>file://${project.build.directory}/mvn-repo</url>
</repository> </repository>
</distributionManagement> </distributionManagement>
<properties> <properties>
@@ -83,4 +191,37 @@
</roles> </roles>
</developer> </developer>
</developers> </developers>
<profiles>
<!-- GPG Signature on release -->
<profile>
<id>release-sign-artifacts</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project> </project>

View File

@@ -1,110 +0,0 @@
0.9.0
======
2020-03-24
* ZF 2.1 Schema/Schematrons
* check against URI allowing for different fragments
* #27 wrong exit code
* now context also loggs
* introduced fatal errors. new errors: filename empty (10), xml not extractable (17), En16931 CEN Schematron error (24)
* fail better if -f missing
* validate against CEN 1.3
* corrected invalidation of complete output status for broken pdfs
* mention filename in report
* escape xml in report elements, e.g. < in criterion to become &lt;
* validation element has been removed from pdf info and added as attribute in root, duration is now direct child of info
* file not found and file too small now without filename
* XML pretty print output. (XML report may now contain header <?xml...)
* First XMLUnit tests
* Better Check of XML Validity also against documents which start with comments or not with xml header <?xml...
* prevent accidental CEN EN16931 application on extended profile
* solved issues when XML structures start with comments instead of root node
* added Symtrax signature
0.8.3
======
2019-10-20
* #22 rounding errors when applying schematron
* check for 1.0 or 2p0 in RDF, not 1.0 and 2.0 like before
* updated to zf 2.0.1
0.8.2
======
2019-10-10
* #22 rounding errors when applying schematron
0.8.1
======
2019-09-01
* added Signature pdfMachine
* added check for additional data correctness
* #23 ZF2 basic was incorrectly checked against Minimum/Basic Without lines Schema/Schematron
* Merged -x and -z to -f
* Created ZUGFeRDValidatorClass and MiscValidatorTests for e.g. tests without existing files
0.8.0
======
2019-07-08
* updated Mustang to mitigate #20 zf1 validation does not always return a <xml> section
* validate not only against *schematron* but also against *schema* files
0.7.0
======
2019-05-31
* ZUGFeRD 2 final compatible
* now displaying number of applied and failed rules
* now failing if no rule could be applied at all
* profileoverride option no longer needed
* version dependent checks for profiles (i.e. comfort is not a valid ZF2 profile!)
* allow new ZF2 filename (zugferd-invoice.xml instead ZUGFeRD-invoice.xml)
* more JUnit tests
* include own version number in XML report
0.6.0
=====
2019-02-15
Factur-X compatible
Mention xpath location where the errors occurred
JUnit tests
new way to collect&handle errors
XMP/PDF-A-Schema extension validation
0.5.0
=====
2018-09-10
Non-16931 profiles are no longer automatically (but still can be manually) checked,
now writing a log file, attempt to find out which toolkit created that particular file (issue #2),
fixing that XML could not be extracted from certain valid PDF/A-3 files (issue #9),
added --action parameter (has to be validate), -f option changes to "-o -z", added APL license,
added possibility to check XML files only, fixing issues with files that contained a
UTF8 BOM in the XML content ("Content not allowed in prolog"),
Upgraded VeraPDF-validation from 1.10.5 to 1.12.1
0.4.3
=====
2018-03-19
Java 8 capability (fixes issue #8)
0.4.2
=====
2018-03-11
POJO embedding VeraPDF: unable to solve some severe deployment issues
0.4.1
=====
2018-02-12
ZUGFeRD 2 public preview EN16931 validation using the schematron files the CEN had
published under APL
0.3.0
=====
2017-07-24
First release as VeraPDF plugin

View File

@@ -189,7 +189,7 @@ Permissive Open Source APL2, see LICENSE
## History ## History
see the [history file](History.md) see the Mustangproject [history file](History.md)
## Authors ## Authors

View File

@@ -1,18 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?> <?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" <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">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>org.mustangproject</groupId> <groupId>org.mustangproject</groupId>
<artifactId>core</artifactId> <artifactId>core</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>2.0.0-alpha4-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId> <groupId>org.mustangproject</groupId>
<artifactId>validator</artifactId> <artifactId>validator</artifactId>
<name>Library to validate Factur-X/ZUGFeRD 1.0 and 2.1 as well as XRechnung e-invoices. </name> <name>Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung)</name>
<packaging>jar</packaging> <packaging>jar</packaging>
<version>2.0.0-SNAPSHOT</version> <version>2.0.0-alpha4-SNAPSHOT</version>
<repositories> <repositories>
<repository> <repository>
<!-- for jargs --> <!-- for jargs -->
@@ -65,7 +64,7 @@
<dependency> <dependency>
<groupId>org.verapdf</groupId> <groupId>org.verapdf</groupId>
<artifactId>validation-model</artifactId> <artifactId>validation-model</artifactId>
<version>1.12.1</version> <version>1.16.1</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.helger/ph-schematron --> <!-- https://mvnrepository.com/artifact/com.helger/ph-schematron -->
<dependency> <dependency>
@@ -76,7 +75,7 @@
<dependency> <dependency>
<groupId>org.mustangproject</groupId> <groupId>org.mustangproject</groupId>
<artifactId>library</artifactId> <artifactId>library</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>2.0.0-alpha4-SNAPSHOT</version>
<!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with <!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with
mvn install:install-file -Dfile=mustang-1.5.4-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.5.4 -Dpackaging=jar -DgeneratePom=true mvn install:install-file -Dfile=mustang-1.5.4-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.5.4 -Dpackaging=jar -DgeneratePom=true
--> -->
@@ -92,13 +91,6 @@
<version>2.6.3</version> <version>2.6.3</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<!-- for commandline options -->
<groupId>com.sanityinc</groupId>
<artifactId>jargs</artifactId>
<version>2.0-SNAPSHOT</version>
</dependency>
<dependency> <dependency>
<groupId>org.riversun</groupId> <groupId>org.riversun</groupId>
<artifactId>bigdoc</artifactId> <artifactId>bigdoc</artifactId>
@@ -107,7 +99,7 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.12</version> <version>4.13.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -125,7 +117,7 @@
</plugins> </plugins>
</pluginManagement> </pluginManagement>
<plugins> <plugins>
<!-- be able to generate XSLT from XRechnung Schematron--> <!-- be able to generate XSLT from XRechnung Schematron
<plugin> <plugin>
<groupId>com.helger.maven</groupId> <groupId>com.helger.maven</groupId>
<artifactId>ph-schematron-maven-plugin</artifactId> <artifactId>ph-schematron-maven-plugin</artifactId>
@@ -141,11 +133,13 @@
</goals> </goals>
</execution> </execution>
</executions> </executions>
</plugin> </plugin> -->
<!-- allow getImplementationVersion for the pom.xml --> <!-- allow getImplementationVersion for the pom.xml -->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration> <configuration>
<archive> <archive>
<manifest> <manifest>
@@ -172,13 +166,6 @@
</configuration> </configuration>
</plugin> </plugin>
<!-- /ZUV --> <!-- /ZUV -->
<!-- generate XSLT files from schematron upon build (goal convert is part
of the preparation of the "package" step)
<plugin> <groupId>com.helger.maven</groupId> <artifactId>ph-sch2xslt-maven-plugin</artifactId>
<version>5.0.8</version> <configuration> <schematronDirectory>${basedir}/src/main/resources/</schematronDirectory>
<xsltDirectory>${basedir}/src/main/resources/xslt</xsltDirectory> </configuration>
<executions> <execution> <goals> <goal>convert</goal> </goals> </execution>
</executions> </plugin> -->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
@@ -212,12 +199,6 @@
<include>**</include> <include>**</include>
</includes> </includes>
</filter> </filter>
<filter>
<artifact>com.sun.xml.bind:jaxb-core</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters> </filters>
</configuration> </configuration>
<executions> <executions>
@@ -240,18 +221,18 @@
<executions> <executions>
<execution> <execution>
<id>copy-zf-schematron-xml-dependencies</id> <id>copy-zf-schematron-xml-dependencies</id>
<phase>validate</phase> <phase>compile</phase>
<goals> <goals>
<goal>copy-resources</goal> <goal>copy-resources</goal>
</goals> </goals>
<configuration> <configuration>
<outputDirectory>${basedir}/xslt/ZF_211/</outputDirectory> <outputDirectory>${basedir}/src/main/resources/xslt/ZF_211/</outputDirectory>
<resources> <resources>
<resource> <resource>
<directory>/schematron/ZF_211/</directory> <directory>${basedir}/src/main/resources/schematron/ZF_211/</directory>
<includes> <includes>
<include>*.xml</include> <include>**/*.xml</include>
</includes> </includes>
</resource> </resource>
</resources> </resources>

View File

@@ -1,94 +0,0 @@
package org.mustangproject.validator;
import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sanityinc.jargs.CmdLineParser;
import com.sanityinc.jargs.CmdLineParser.Option;
public class Main {
static final ClassLoader cl = Main.class.getClassLoader();
private static final Logger LOGGER = LoggerFactory.getLogger(Main.class.getCanonicalName()); // log output is
// ignored for the
// time being
public void run(String[] args) {
/***
* prerequisite is a mvn generate-resources
*/
CmdLineParser parser = new CmdLineParser();
Option<String> actionOption = parser.addStringOption('a', "action");
Option<String> filenameOption = parser.addStringOption('f', "Filename");
Option<Boolean> licenseOption = parser.addBooleanOption('l', "license");
Option<Boolean> helpOption = parser.addBooleanOption('h', "help");
Option<String> logAppendOption = parser.addStringOption("logAppend");
boolean optionsRecognized = false;
try {
parser.parse(args);
} catch (CmdLineParser.OptionException e) {
System.err.println(e.getMessage());
System.exit(-2);
}
Boolean helpRequested = parser.getOptionValue(helpOption);
if (parser.getOptionValue(licenseOption) != null) {
optionsRecognized = true;
System.out.println("Copyright 2018 Jochen Stärk\n" + "\n"
+ "Licensed under the Apache License, Version 2.0 (the \"License\");\n"
+ "you may not use this file except in compliance with the License.\n"
+ "You may obtain a copy of the License at\n" + "\n"
+ " http://www.apache.org/licenses/LICENSE-2.0\n" + "\n"
+ "Unless required by applicable law or agreed to in writing, software\n"
+ "distributed under the License is distributed on an \"AS IS\" BASIS,\n"
+ "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
+ "See the License for the specific language governing permissions and\n"
+ "limitations under the License.\n\n\n\n\n"
+ "This software is embedding the PDF/A validator VeraPDF, "
+ "http://verapdf.org/, which is available under GPL and MPL licenses.");
System.exit(0);
}
String filename = parser.getOptionValue(filenameOption);
String action = parser.getOptionValue(actionOption);
File logdir = new File("log");
if (!logdir.exists() || !logdir.isDirectory() || !logdir.canWrite()) {
System.err.println("Need writable subdirectory 'log' for log files.");
}
if ((action != null) && (action.equals("validate"))) {
ZUGFeRDValidator zfv=new ZUGFeRDValidator();
zfv.setLogAppend(parser.getOptionValue(logAppendOption));
System.out.println(zfv.validate(filename));
optionsRecognized = !zfv.hasOptionsError();
if (!zfv.wasCompletelyValid()) {
System.exit(-1);
}
}
if ((!optionsRecognized) || (helpRequested != null && helpRequested.booleanValue())) {
System.out.println(
"usage: --action validate --source <ZUGFeRD PDF Filename.pdf>|<ZUGFeRD XML Filename.xml> [-l (shows license)][--logAppend \"String to be appended to validation result log\"]");
System.exit(-1);
}
}
public static void main(String[] args) {
new Main().run(args);
}
}

View File

@@ -220,7 +220,7 @@ public class PDFValidator extends Validator {
} }
boolean documentFilenameValid=false; boolean documentFilenameValid=false;
for (int i = 0; i < nodes.getLength(); i++) { for (int i = 0; i < nodes.getLength(); i++) {
String[] valueArray = { "factur-x.xml", "ZUGFeRD-invoice.xml", "zugferd-invoice.xml" }; String[] valueArray = { "factur-x.xml", "ZUGFeRD-invoice.xml", "zugferd-invoice.xml", "xrechnung.xml" };
if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) { if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) {
documentFilenameValid=true; documentFilenameValid=true;
} }
@@ -246,7 +246,7 @@ public class PDFValidator extends Validator {
boolean versionValid=false; boolean versionValid=false;
for (int i = 0; i < nodes.getLength(); i++) { for (int i = 0; i < nodes.getLength(); i++) {
String[] valueArray = { "1.0", "2p0" }; String[] valueArray = { "1.0", "2p0", "1p2" }; //1p2 is for xrechnung 1.2, 2p0 can be ZF 2.0, 2.1, 2.1.1 or XRechnung 2
if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) { if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) {
versionValid=true; versionValid=true;
} // e.g. 1.0 } // e.g. 1.0
@@ -277,6 +277,7 @@ public class PDFValidator extends Validator {
byte[] intarsysSignature = "intarsys ".getBytes("UTF-8"); byte[] intarsysSignature = "intarsys ".getBytes("UTF-8");
byte[] konikSignature = "Konik".getBytes("UTF-8"); byte[] konikSignature = "Konik".getBytes("UTF-8");
byte[] pdfMachineSignature = "pdfMachine from Broadgun Software".getBytes("UTF-8"); byte[] pdfMachineSignature = "pdfMachine from Broadgun Software".getBytes("UTF-8");
byte[] ghostscriptSignature = "%%Invocation:".getBytes("UTF-8");
if (searcher.indexOf(file, symtraxSignature) != -1) { if (searcher.indexOf(file, symtraxSignature) != -1) {
Signature = "Symtrax"; Signature = "Symtrax";
@@ -290,6 +291,8 @@ public class PDFValidator extends Validator {
Signature = "Konik"; Signature = "Konik";
} else if (searcher.indexOf(file, pdfMachineSignature) != -1) { } else if (searcher.indexOf(file, pdfMachineSignature) != -1) {
Signature = "pdfMachine"; Signature = "pdfMachine";
} else if (searcher.indexOf(file, ghostscriptSignature) != -1) {
Signature = "Ghostscript";
} }
context.setSignature(Signature); context.setSignature(Signature);

View File

@@ -20,11 +20,11 @@ import javax.xml.transform.stream.StreamSource;
public class SchematronPipeline { public class SchematronPipeline {
static final ClassLoader cl = SchematronPipeline.class.getClassLoader(); static final ClassLoader cl = SchematronPipeline.class.getClassLoader();
private static final TransformerFactory factory = getTransformerFactory(); private static final TransformerFactory factory = getTransformerFactory();
private static final String xslExt = ".xsl"; //$NON-NLS-1$ private static final String xslExt = ".xsl";
private static final String resourcePath = "iso-schematron-xslt2/"; //$NON-NLS-1$ private static final String resourcePath = "iso-schematron-xslt2/";
private static final String isoDsdlXsl = resourcePath + "iso_dsdl_include" + xslExt; //$NON-NLS-1$ private static final String isoDsdlXsl = resourcePath + "iso_dsdl_include" + xslExt;
private static final String isoExpXsl = resourcePath + "iso_abstract_expand" + xslExt; //$NON-NLS-1$ private static final String isoExpXsl = resourcePath + "iso_abstract_expand" + xslExt;
private static final String isoSvrlXsl = resourcePath + "iso_svrl_for_xslt2" + xslExt; //$NON-NLS-1$ private static final String isoSvrlXsl = resourcePath + "iso_svrl_for_xslt2" + xslExt;
private static final Templates cachedIsoDsdXsl = createCachedTransform(isoDsdlXsl); private static final Templates cachedIsoDsdXsl = createCachedTransform(isoDsdlXsl);
private static final Templates cachedExpXsl = createCachedTransform(isoExpXsl); private static final Templates cachedExpXsl = createCachedTransform(isoExpXsl);
private static final Templates cachedIsoSvrlXsl = createCachedTransform(isoSvrlXsl); private static final Templates cachedIsoSvrlXsl = createCachedTransform(isoSvrlXsl);
@@ -39,16 +39,16 @@ public class SchematronPipeline {
try { try {
return factory.newTemplates(new StreamSource(cl.getResourceAsStream(transName))); return factory.newTemplates(new StreamSource(cl.getResourceAsStream(transName)));
} catch (TransformerConfigurationException excep) { } catch (TransformerConfigurationException excep) {
throw new IllegalStateException("Policy Schematron transformer XSL " + transName + " not found.", excep); //$NON-NLS-1$ //$NON-NLS-2$ throw new IllegalStateException("Policy Schematron transformer XSL " + transName + " not found.", excep); //$NON-NLS-2$
} }
} }
public static void processSchematron(InputStream schematronSource, OutputStream xslDest) public static void processSchematron(InputStream schematronSource, OutputStream xslDest)
throws TransformerException, IOException { throws TransformerException, IOException {
File isoDsdResult = createTempFileResult(cachedIsoDsdXsl.newTransformer(), new StreamSource(schematronSource), File isoDsdResult = createTempFileResult(cachedIsoDsdXsl.newTransformer(), new StreamSource(schematronSource),
"IsoDsd"); //$NON-NLS-1$ "IsoDsd");
File isoExpResult = createTempFileResult(cachedExpXsl.newTransformer(), new StreamSource(isoDsdResult), File isoExpResult = createTempFileResult(cachedExpXsl.newTransformer(), new StreamSource(isoDsdResult),
"ExpXsl"); //$NON-NLS-1$ "ExpXsl");
cachedIsoSvrlXsl.newTransformer().transform(new StreamSource(isoExpResult), new StreamResult(xslDest)); cachedIsoSvrlXsl.newTransformer().transform(new StreamSource(isoExpResult), new StreamResult(xslDest));
isoDsdResult.delete(); isoDsdResult.delete();
isoExpResult.delete(); isoExpResult.delete();
@@ -56,7 +56,7 @@ public class SchematronPipeline {
private static File createTempFileResult(final Transformer transformer, final StreamSource toTransform, private static File createTempFileResult(final Transformer transformer, final StreamSource toTransform,
final String suffix) throws TransformerException, IOException { final String suffix) throws TransformerException, IOException {
File result = File.createTempFile("ZUV_", suffix); //$NON-NLS-1$ File result = File.createTempFile("ZUV_", suffix);
result.deleteOnExit(); result.deleteOnExit();
try (FileOutputStream fos = new FileOutputStream(result)) { try (FileOutputStream fos = new FileOutputStream(result)) {

View File

@@ -26,17 +26,34 @@ public abstract class Validator {
//abstract method //abstract method
/***
* prepare validation
* @param filename the filename of the xml file to be examined
* @throws IrrecoverableValidationError when any fatal errors arise, e.g. when the source file can not be found
*/
public abstract void setFilename(String filename) throws IrrecoverableValidationError; public abstract void setFilename(String filename) throws IrrecoverableValidationError;
/***
* perform the validation
* @throws IrrecoverableValidationError any fatal errors, e.g. when the source file can not be found
*/
public abstract void validate() throws IrrecoverableValidationError; public abstract void validate() throws IrrecoverableValidationError;
/**
* get validation result
* @return validation result as xml string
*/
public String getXMLResult() { public String getXMLResult() {
return context.getXMLResult(); return context.getXMLResult();
} }
/*** /***
* validates a schema, which can only be needed in XML validation - and in pdf validation for additional data * validates a schema, which can only be needed in XML validation - and in pdf validation for additional data
* @param xmlRawData * @param xmlRawData the XML to be validated
* @param schemaPath * @param schemaPath the filename of the schema file
* @param section the error message type code
* @param part whether the error message occurs in the pdf or xml part
* @throws IrrecoverableValidationError when any fatal errors arise, e.g. when the source file can not be found
*/ */
protected void validateSchema(byte[] xmlRawData, String schemaPath, int section, EPart part) throws IrrecoverableValidationError { protected void validateSchema(byte[] xmlRawData, String schemaPath, int section, EPart part) throws IrrecoverableValidationError {
URL schemaFile = ClassLoader.getSystemResource("schema/" + schemaPath); URL schemaFile = ClassLoader.getSystemResource("schema/" + schemaPath);

View File

@@ -33,9 +33,6 @@ import com.helger.schematron.svrl.SVRLHelper;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
public class XMLValidator extends Validator { public class XMLValidator extends Validator {
public XMLValidator(ValidationContext ctx) {
super(ctx);
}
private static final Logger LOGGER = LoggerFactory.getLogger(XMLValidator.class.getCanonicalName()); // log output private static final Logger LOGGER = LoggerFactory.getLogger(XMLValidator.class.getCanonicalName()); // log output
// is // is
@@ -46,8 +43,19 @@ public class XMLValidator extends Validator {
protected String filename = ""; protected String filename = "";
int firedRules = 0; int firedRules = 0;
int failedRules = 0; int failedRules = 0;
boolean disableNotices = false;
ISchematronResource aResSCH = null; ISchematronResource aResSCH = null;
public XMLValidator(ValidationContext ctx) {
super(ctx);
}
/***
* set source file
* @param name
* @throws IrrecoverableValidationError
*/
public void setFilename(String name) throws IrrecoverableValidationError { // from XML Filename public void setFilename(String name) throws IrrecoverableValidationError { // from XML Filename
filename = name; filename = name;
// file existence must have been checked before // file existence must have been checked before
@@ -66,21 +74,36 @@ public class XMLValidator extends Validator {
} }
} }
/***
* manually set the xml content
* @param xml the xml to be checked
*/
public void setStringContent(String xml) { public void setStringContent(String xml) {
zfXML = xml; zfXML = xml;
} }
/**
* whether uri1 has the same meaning like uri1 (it has, if it only differs in the fragment, i.e. uri1#1==uri1#2 )
* @param uri1
* @param uri2
* @return true if semantically identical
*/
public static boolean matchesURI(String uri1, String uri2) { public static boolean matchesURI(String uri1, String uri2) {
return (uri1.equals(uri2) || uri1.startsWith(uri2 + "#")); return (uri1.equals(uri2) || uri1.startsWith(uri2 + "#"));
} }
/*** /***
* * don't report notices in validation report
* @param xmlString */
* @param overrideProfileCheck public void disableNotices() {
* if set to true, all ZF2 files will be checked against EN16931 disableNotices = true;
* schematron, since no other schematron is available }
* @return
/***
* perform validation
* @throws IrrecoverableValidationError if any fatal errors occur, e.g. source file can not be read
*/ */
@Override @Override
public void validate() throws IrrecoverableValidationError { public void validate() throws IrrecoverableValidationError {
@@ -260,12 +283,13 @@ public class XMLValidator extends Validator {
validateSchematron(zfXML, xsltFilename, 4, ESeverity.error); validateSchematron(zfXML, xsltFilename, 4, ESeverity.error);
if (context.getVersion().equals("2") if (context.getVersion().equals("2")
&& isEN16931) { && (isEN16931 || isXRechnung)) {
//additionally validate against CEN //additionally validate against CEN
validateSchematron(zfXML, "/xslt/cii16931schematron/EN16931-CII-validation.xslt", 24, ESeverity.error); validateSchematron(zfXML, "/xslt/cii16931schematron/EN16931-CII-validation.xslt", 24, ESeverity.error);
if (!disableNotices || XrechnungSeverity != ESeverity.notice) {
validateXR(zfXML, XrechnungSeverity); validateXR(zfXML, XrechnungSeverity);
} }
}
} catch (IrrecoverableValidationError er) { } catch (IrrecoverableValidationError er) {
@@ -285,17 +309,32 @@ public class XMLValidator extends Validator {
context.addCustomXML("<info><version>" + ((context.getVersion() != null) ? context.getVersion() : "invalid") context.addCustomXML("<info><version>" + ((context.getVersion() != null) ? context.getVersion() : "invalid")
+ "</version><profile>" + ((context.getProfile() != null) ? context.getProfile() : "invalid") + + "</version><profile>" + ((context.getProfile() != null) ? context.getProfile() : "invalid") +
"</profile><validator version=\"" + Main.class.getPackage().getImplementationVersion() + "\"></validator><rules><fired>" + firedRules + "</fired><failed>" + failedRules + "</failed></rules>" + "<duration unit='ms'>" + (endTime - startXMLTime) + "</duration></info>"); "</profile><validator version=\"" + XMLValidator.class.getPackage().getImplementationVersion() + "\"></validator><rules><fired>" + firedRules + "</fired><failed>" + failedRules + "</failed></rules>" + "<duration unit='ms'>" + (endTime - startXMLTime) + "</duration></info>");
} }
public void validateXR(String xml, ESeverity errorImpact) throws IrrecoverableValidationError { public void validateXR(String xml, ESeverity errorImpact) throws IrrecoverableValidationError {
validateSchematron(xml, "/xslt/XR/XRechnung-CII-validation.xslt",27, errorImpact); //Guideline ID=urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_1.2 or
if (xml.contains(":xrechnung_1.")) {
// urn:cen.eu:en16931:2017#compliant#urn:xoev-dede:kosit:standard:xrechnung_2.0#conformant#urn:xoev-de:kosit:extension:xrechnung_2.0
validateSchematron(xml, "/xslt/XR_12/XRechnung-CII-validation.xslt", 27, errorImpact);
} else {
// urn:cen.eu:en16931:2017#compliant#urn:xoev-dede:kosit:standard:xrechnung_2.0#conformant#urn:xoev-de:kosit:extension:xrechnung_2.0
validateSchematron(xml, "/xslt/XR_20/XRechnung-CII-validation.xslt", 27, errorImpact);
}
} }
/***
* validate using a xslt file generated from a schematron in the build preparation of this software
* @param xml the xml to be checked
* @param xsltFilename the filename of the intermediate XSLT file
* @param section the error type code, if one arises
* @param severity how serious a error should be treated - may only be notice
* @throws IrrecoverableValidationError if anything happened that prevents further checks
*/
public void validateSchematron(String xml, String xsltFilename, int section, ESeverity severity) throws IrrecoverableValidationError { public void validateSchematron(String xml, String xsltFilename, int section, ESeverity severity) throws IrrecoverableValidationError {
ISchematronResource aResSCH = null; ISchematronResource aResSCH = null;
aResSCH = SchematronResourceXSLT.fromClassPath(xsltFilename); aResSCH = SchematronResourceXSLT.fromClassPath(xsltFilename);

View File

@@ -39,6 +39,7 @@ public class ZUGFeRDValidator {
protected boolean displayXMLValidationOutput; protected boolean displayXMLValidationOutput;
protected long startTime; protected long startTime;
protected boolean optionsRecognized; protected boolean optionsRecognized;
protected boolean disableNotices = false;
protected String Signature; protected String Signature;
protected boolean wasCompletelyValid = false; protected boolean wasCompletelyValid = false;
protected String logAppend=null; protected String logAppend=null;
@@ -77,7 +78,7 @@ public class ZUGFeRDValidator {
boolean xmlValidity; boolean xmlValidity;
context.clear(); context.clear();
StringBuffer finalStringResult = new StringBuffer(); StringBuffer finalStringResult = new StringBuffer();
SimpleDateFormat isoDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$ SimpleDateFormat isoDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(); Date date = new Date();
startTime = Calendar.getInstance().getTimeInMillis(); startTime = Calendar.getInstance().getTimeInMillis();
try { try {
@@ -110,7 +111,9 @@ public class ZUGFeRDValidator {
} else { } else {
BigFileSearcher searcher = new BigFileSearcher(); BigFileSearcher searcher = new BigFileSearcher();
XMLValidator xv = new XMLValidator(context); XMLValidator xv = new XMLValidator(context);
if (disableNotices) {
xv.disableNotices();
}
byte[] pdfSignature = { '%', 'P', 'D', 'F' }; byte[] pdfSignature = { '%', 'P', 'D', 'F' };
boolean isPDF = searcher.indexOf(file, pdfSignature) == 0; boolean isPDF = searcher.indexOf(file, pdfSignature) == 0;
if (isPDF) { if (isPDF) {
@@ -250,6 +253,12 @@ public class ZUGFeRDValidator {
return sw.toString(); return sw.toString();
} }
/***
* don't report notices in validation report
*/
public void disableNotices() {
disableNotices=true;
}
/** /**
* Read the file and calculate the SHA-1 checksum * Read the file and calculate the SHA-1 checksum
* *

View File

@@ -1,6 +1,7 @@
<configuration> <configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder> <encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder> </encoder>
@@ -24,6 +25,6 @@
<!-- Configure so that it outputs to both console and log file --> <!-- Configure so that it outputs to both console and log file -->
<root level="INFO"> <root level="INFO">
<appender-ref ref="FILE" /> <appender-ref ref="FILE" />
<!-- appender-ref ref="STDOUT" /--> <!-- appender-ref ref="STDERR" /-->
</root> </root>
</configuration> </configuration>

View File

@@ -0,0 +1,61 @@
<pattern xmlns="http://purl.oclc.org/dsdl/schematron" is-a="model"
id="CII-model">
<param name="BR-DE-01"
value="rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans" />
<param name="BR-DE-02" value="ram:DefinedTradeContact" />
<param name="BR-DE-03" value="ram:CityName[boolean(normalize-space(.))]" />
<param name="BR-DE-04" value="ram:PostcodeCode[boolean(normalize-space(.))]" />
<param name="BR-DE-05"
value="(ram:PersonName,ram:DepartmentName)[boolean(normalize-space(.))]" />
<param name="BR-DE-06"
value="ram:TelephoneUniversalCommunication/ram:CompleteNumber[boolean(normalize-space(.))]" />
<param name="BR-DE-07"
value="ram:EmailURIUniversalCommunication/ram:URIID[boolean(normalize-space(.))]" />
<param name="BR-DE-08" value="ram:CityName[boolean(normalize-space(.))]" />
<param name="BR-DE-09" value="ram:PostcodeCode[boolean(normalize-space(.))]" />
<param name="BR-DE-10" value="ram:CityName[boolean(normalize-space(.))]" />
<param name="BR-DE-11" value="ram:PostcodeCode[boolean(normalize-space(.))]" />
<!-- Für BG-19 wird jedes Informationselement der Gruppe einzeln aufgeführt, der Pfad zu BG-19 (DIRECT DEBIT) zu unspezifisch ist und
sich mit den Pfaden zu BG-17 und BG-18 überschneidet. -->
<param name="BR-DE-13"
value="count((rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans/ram:PayeePartyCreditorFinancialAccount)[1]) + count(rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans/ram:ApplicableTradeSettlementFinancialCard) + count((rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms/ram:DirectDebitMandateID, rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:CreditorReferenceID, rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans/ram:PayerPartyDebtorFinancialAccount/ram:IBANID)[1]) = 1" />
<param name="BR-DE-14"
value="ram:RateApplicablePercent[boolean(normalize-space(.))]" />
<param name="BR-DE-15"
value="rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerReference[boolean(normalize-space(.))]" />
<param name="BR-DE-16"
value="(rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID='VA' or @schemeID='VAT' or @schemeID='FC'][boolean(normalize-space(.))], rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTaxRepresentativeTradeParty)" />
<param name="BR-DE-17"
value="rsm:ExchangedDocument/ram:TypeCode = ('326', '380', '384', '389', '381', '875', '876', '877')" />
<param name="BR-DE-18"
value="every $line in rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms/ram:Description/tokenize(.,'(\r\n|\r|\n)') satisfies if(count(tokenize($line,'#')) &gt; 1) then tokenize($line,'#')[1]='' and (tokenize($line,'#')[2]='SKONTO' or tokenize($line,'#')[2]='VERZUG') and string-length(replace(tokenize($line,'#')[3],'TAGE=[0-9]+',''))=0 and string-length(replace(tokenize($line,'#')[4],'PROZENT=[0-9]+\.[0-9]{2}',''))=0 and (tokenize($line,'#')[5]='' and empty(tokenize($line,'#')[6]) or string-length(replace(tokenize($line,'#')[5],'BASISBETRAG=[0-9]+\.[0-9]{2}',''))=0 and tokenize($line,'#')[6]='' and empty(tokenize($line,'#')[7])) else true()" />
<param name="BR-DE-19"
value="not(ram:TypeCode = '58') or matches(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')), '^[A-Z]{2}[0-9]{2}[a-zA-Z0-9]{0,30}$') and xs:integer(string-join(for $cp in string-to-codepoints(concat(substring(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),5),upper-case(substring(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),1,2)),substring(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),3,2))) return (if($cp > 64) then $cp - 55 else $cp - 48),'')) mod 97 = 1" />
<param name="BR-DE-20"
value="not(ram:TypeCode = '59') or matches(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')), '^[A-Z]{2}[0-9]{2}[a-zA-Z0-9]{0,30}$') and xs:integer(string-join(for $cp in string-to-codepoints(concat(substring(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),5),upper-case(substring(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),1,2)),substring(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),3,2))) return (if($cp > 64) then $cp - 55 else $cp - 48),'')) mod 97 = 1" />
<param name="BR-DE-21"
value="ram:GuidelineSpecifiedDocumentContextParameter/ram:ID = 'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0'" />
<param name="INVOICE" value="//rsm:CrossIndustryInvoice" />
<param name="BG-2_PROCESS_CONTROL"
value="/rsm:CrossIndustryInvoice/rsm:ExchangedDocumentContext" />
<param name="BG-4_SELLER"
value="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty" />
<param name="BG-5_SELLER_POSTAL_ADDRESS"
value="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:PostalTradeAddress" />
<param name="BG-6_SELLER_CONTACT"
value="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:DefinedTradeContact" />
<param name="BG-8_BUYER_POSTAL_ADDRESS"
value="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty/ram:PostalTradeAddress" />
<param name="BG-15_DELIVER_TO_ADDRESS"
value="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:PostalTradeAddress" />
<param name="BG-16_PAYMENT_INSTRUCTIONS"
value="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans" />
<param name="BG-23_VAT_BREAKDOWN"
value="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:ApplicableTradeTax" />
</pattern>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron"
xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ccts="urn:un:unece:uncefact:documentation:standard:CoreComponentsTechnicalSpecification:2"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
schemaVersion="2.0.0" queryBinding="xslt2">
<title>Schematron Version @xr-schematron.version.full@ - XRechnung
@xrechnung.version@ compatible - CII</title>
<ns prefix="rsm"
uri="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" />
<ns prefix="ccts"
uri="urn:un:unece:uncefact:documentation:standard:CoreComponentsTechnicalSpecification:2" />
<ns prefix="udt"
uri="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" />
<ns prefix="qdt"
uri="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" />
<ns prefix="ram"
uri="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" />
<phase id="XRechnung_model">
<active pattern="CII-model" />
</phase>
<!-- Abstract CEN BII patterns -->
<!-- ========================= -->
<include href="abstract/XRechnung-model.part" />
<!-- Data Binding parameters -->
<!-- ======================= -->
<include href="CII/XRechnung-CII-model.part" />
</schema>

View File

@@ -0,0 +1,64 @@
<pattern xmlns="http://purl.oclc.org/dsdl/schematron" abstract="true" id="model">
<rule context="$INVOICE">
<assert test="$BR-DE-01" flag="fatal" id="BR-DE-1"
>[BR-DE-1] Eine Rechnung (INVOICE) muss Angaben zu "PAYMENT INSTRUCTIONS" (BG-16) enthalten.</assert>
<assert test="$BR-DE-13" flag="fatal" id="BR-DE-13"
>[BR-DE-13] In der Rechnung müssen Angaben zu genau einer der drei Gruppen "CREDIT TRANSFER" (BG-17), "PAYMENT CARD INFORMATION" (BG-18) oder "DIRECT DEBIT" (BG-19) übermittelt werden.</assert>
<assert test="$BR-DE-15" flag="fatal" id="BR-DE-15"
>[BR-DE-15] Das Element "Buyer reference" (BT-10) muss übermittelt werden.</assert>
<assert test="$BR-DE-16" flag="fatal" id="BR-DE-16"
>[BR-DE-16] In der Rechnung muss mindestens eines der Elemente "Seller VAT identifier" (BT-31), "Seller tax registration identifier" (BT-32) oder "SELLER TAX REPRESENTATIVE PARTY" (BG-11) übermittelt werden.</assert>
<assert test="$BR-DE-17" flag="warning" id="BR-DE-17" >[BR-DE-17] Mit dem Element "Invoice type code" (BT-3) sollen ausschließlich folgende Codes aus der Codeliste UNTDID 1001 übermittelt werden: 326 (Partial invoice), 380 (Commercial invoice), 384 (Corrected invoice), 389 (Self-billed invoice) und 381 (Credit note),875 (Partial construction invoice), 876 (Partial final construction invoice), 877 (Final construction invoice).</assert>
<assert test="$BR-DE-18" flag="fatal" id="BR-DE-18"
>[BR-DE-18] Die Informationen zur Gewährung von Skonto oder zur Berechnung von Verzugszinsen müssen wie folgt im Element "Payment terms" (BT-20) übermittelt werden: Anzugeben ist im ersten Segment "SKONTO" oder "VERZUG", im zweiten "TAGE=n", im dritten "PROZENT=n". Prozentzahlen sind ohne Vorzeichen sowie mit Punkt getrennt von zwei Nachkommastellen anzugeben. Liegt dem zu berechnenden Betrag nicht BT-115, "fälliger Betrag" zugrunde, sondern nur ein Teil des fälligen Betrags der Rechnung, ist der Grundwert zur Berechnung von Skonto oder Verzugszins als viertes Segment "BASISBETRAG=n" gemäß dem semantischen Datentypen Amount anzugeben. Jeder Eintrag beginnt mit einer #, die Segmente sind mit einer # getrennt und eine Zeile schließt mit einer # ab. Am Ende einer vollständigen Skonto oder Verzugsangabe muss ein XML-konformer Zeilenumbruch folgen. Alle Angaben zur Gewährung von Skonto oder zur Berechnung von Verzugszinsen müssen in Großbuchstaben gemacht werden. Zusätzliches Whitespace (Leerzeichen, Tabulatoren oder Zeilenumbrüche) ist nicht zulässig. Andere Zeichen oder Texte als in den oberen Vorgaben genannt sind nicht zulässig.</assert>
<assert
test="count(//ram:AdditionalReferencedDocument) = count(//ram:AdditionalReferencedDocument[not(./ram:AttachmentBinaryObject/@filename = preceding-sibling::ram:AdditionalReferencedDocument/ram:AttachmentBinaryObject/@filename)])"
flag="fatal" id="BR-DE-22"
>[BR-DE-22] Not all filename attributes of the embeddedDocumentBinaryObject elements are unique
</assert>
</rule>
<rule context="$BG-2_PROCESS_CONTROL">
<assert test="$BR-DE-21" flag="warning" id="BR-DE-21"
>[BR-DE-21] Das Element "Specification identifier" (BT-24) soll syntaktisch der Kennung des Standards XRechnung entsprechen.</assert>
</rule>
<rule context="$BG-4_SELLER">
<assert test="$BR-DE-02" flag="fatal" id="BR-DE-2"
>[BR-DE-2] Die Gruppe "SELLER CONTACT" (BG-6) muss übermittelt werden.</assert>
</rule>
<rule context="$BG-5_SELLER_POSTAL_ADDRESS">
<assert test="$BR-DE-03" flag="fatal" id="BR-DE-3"
>[BR-DE-3] Das Element "Seller city" (BT-37) muss übermittelt werden.</assert>
<assert test="$BR-DE-04" flag="fatal" id="BR-DE-4"
>[BR-DE-4] Das Element "Seller post code" (BT-38) muss übermittelt werden.</assert>
</rule>
<rule context="$BG-6_SELLER_CONTACT">
<assert test="$BR-DE-05" flag="fatal" id="BR-DE-5"
>[BR-DE-5] Das Element "Seller contact point" (BT-41) muss übermittelt werden.</assert>
<assert test="$BR-DE-06" flag="fatal" id="BR-DE-6"
>[BR-DE-6] Das Element "Seller contact telephone number" (BT-42) muss übermittelt werden.</assert>
<assert test="$BR-DE-07" flag="fatal" id="BR-DE-7"
>[BR-DE-7] Das Element "Seller contact email address" (BT-43) muss übermittelt werden.</assert>
</rule>
<rule context="$BG-8_BUYER_POSTAL_ADDRESS">
<assert test="$BR-DE-08" flag="fatal" id="BR-DE-8"
>[BR-DE-8] Das Element "Buyer city" (BT-52) muss übermittelt werden.</assert>
<assert test="$BR-DE-09" flag="fatal" id="BR-DE-9"
>[BR-DE-9] Das Element "Buyer post code" (BT-53) muss übermittelt werden.</assert>
</rule>
<rule context="$BG-15_DELIVER_TO_ADDRESS">
<assert test="$BR-DE-10" flag="fatal" id="BR-DE-10"
>[BR-DE-10] Das Element "Deliver to city" (BT-77) muss übermittelt werden, wenn die Gruppe "DELIVER TO ADDRESS" (BG-15) übermittelt wird.</assert>
<assert test="$BR-DE-11" flag="fatal" id="BR-DE-11"
>[BR-DE-11] Das Element "Deliver to post code" (BT-78) muss übermittelt werden, wenn die Gruppe "DELIVER TO ADDRESS" (BG-15) übermittelt wird.</assert>
</rule>
<rule context="$BG-16_PAYMENT_INSTRUCTIONS">
<assert test="$BR-DE-19" flag="fatal" id="BR-DE-19"
>[BR-DE-19] "Payment account identifier" (BT-84) soll eine korrekte IBAN enthalten, wenn in "Payment means type code" (BT-81) mit dem Code 58 SEPA als Zahlungsmittel gefordert wird.</assert>
<assert test="$BR-DE-20" flag="warning" id="BR-DE-20"
>[BR-DE-20] "Debited account identifier" (BT-91) soll eine korrekte IBAN enthalten, wenn in "Payment means type code" (BT-81) mit dem Code 59 SEPA als Zahlungsmittel gefordert wird.</assert>
</rule>
<rule context="$BG-23_VAT_BREAKDOWN">
<assert test="$BR-DE-14" flag="fatal" id="BR-DE-14"
>[BR-DE-14] Das Element "VAT category rate" (BT-119) muss übermittelt werden.</assert>
</rule>
</pattern>

View File

@@ -9107,7 +9107,7 @@
</pattern> </pattern>
<pattern> <pattern>
<rule context="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode"> <rule context="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode">
<let name="codeValue5" value="."/> <let name="codeValue5" value="@listID"/>
<assert test="document(&apos;FACTUR-X_EN16931_codedb.xml&apos;)//cl[@id=5]/enumeration[@value=$codeValue5]"> <assert test="document(&apos;FACTUR-X_EN16931_codedb.xml&apos;)//cl[@id=5]/enumeration[@value=$codeValue5]">
Value of 'ram:ClassCode' is not allowed.</assert> Value of 'ram:ClassCode' is not allowed.</assert>
</rule> </rule>

View File

@@ -19688,7 +19688,7 @@
</pattern> </pattern>
<pattern> <pattern>
<rule context="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode"> <rule context="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode">
<let name="codeValue7" value="."/> <let name="codeValue7" value="@listID"/>
<assert test="document(&apos;FACTUR-X_EXTENDED_codedb.xml&apos;)//cl[@id=7]/enumeration[@value=$codeValue7]"> <assert test="document(&apos;FACTUR-X_EXTENDED_codedb.xml&apos;)//cl[@id=7]/enumeration[@value=$codeValue7]">
Value of 'ram:ClassCode' is not allowed.</assert> Value of 'ram:ClassCode' is not allowed.</assert>
<assert test="@listID"> <assert test="@listID">

View File

@@ -0,0 +1,560 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsl:stylesheet xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:ccts="urn:un:unece:uncefact:documentation:standard:CoreComponentsTechnicalSpecification:2" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:saxon="http://saxon.sf.net/" xmlns:schold="http://www.ascc.net/xml/schematron" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<!--Implementers: please note that overriding process-prolog or process-root is
the preferred method for meta-stylesheets to use where possible. -->
<xsl:param name="archiveDirParameter" />
<xsl:param name="archiveNameParameter" />
<xsl:param name="fileNameParameter" />
<xsl:param name="fileDirParameter" />
<xsl:variable name="document-uri">
<xsl:value-of select="document-uri(/)" />
</xsl:variable>
<!--PHASES-->
<!--PROLOG-->
<xsl:output indent="yes" method="xml" omit-xml-declaration="no" standalone="yes" />
<!--XSD TYPES FOR XSLT2-->
<!--KEYS AND FUNCTIONS-->
<!--DEFAULT RULES-->
<!--MODE: SCHEMATRON-SELECT-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<xsl:template match="*" mode="schematron-select-full-path">
<xsl:apply-templates mode="schematron-get-full-path" select="." />
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<xsl:template match="*" mode="schematron-get-full-path">
<xsl:apply-templates mode="schematron-get-full-path" select="parent::*" />
<xsl:text>/</xsl:text>
<xsl:choose>
<xsl:when test="namespace-uri()=''">
<xsl:value-of select="name()" />
</xsl:when>
<xsl:otherwise>
<xsl:text>*:</xsl:text>
<xsl:value-of select="local-name()" />
<xsl:text>[namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()" />
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:variable name="preceding" select="count(preceding-sibling::*[local-name()=local-name(current()) and namespace-uri() = namespace-uri(current())])" />
<xsl:text>[</xsl:text>
<xsl:value-of select="1+ $preceding" />
<xsl:text>]</xsl:text>
</xsl:template>
<xsl:template match="@*" mode="schematron-get-full-path">
<xsl:apply-templates mode="schematron-get-full-path" select="parent::*" />
<xsl:text>/</xsl:text>
<xsl:choose>
<xsl:when test="namespace-uri()=''">@<xsl:value-of select="name()" />
</xsl:when>
<xsl:otherwise>
<xsl:text>@*[local-name()='</xsl:text>
<xsl:value-of select="local-name()" />
<xsl:text>' and namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()" />
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-2-->
<!--This mode can be used to generate prefixed XPath for humans-->
<xsl:template match="node() | @*" mode="schematron-get-full-path-2">
<xsl:for-each select="ancestor-or-self::*">
<xsl:text>/</xsl:text>
<xsl:value-of select="name(.)" />
<xsl:if test="preceding-sibling::*[name(.)=name(current())]">
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1" />
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="not(self::*)">
<xsl:text />/@<xsl:value-of select="name(.)" />
</xsl:if>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-3-->
<!--This mode can be used to generate prefixed XPath for humans
(Top-level element has index)-->
<xsl:template match="node() | @*" mode="schematron-get-full-path-3">
<xsl:for-each select="ancestor-or-self::*">
<xsl:text>/</xsl:text>
<xsl:value-of select="name(.)" />
<xsl:if test="parent::*">
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1" />
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="not(self::*)">
<xsl:text />/@<xsl:value-of select="name(.)" />
</xsl:if>
</xsl:template>
<!--MODE: GENERATE-ID-FROM-PATH -->
<xsl:template match="/" mode="generate-id-from-path" />
<xsl:template match="text()" mode="generate-id-from-path">
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
<xsl:value-of select="concat('.text-', 1+count(preceding-sibling::text()), '-')" />
</xsl:template>
<xsl:template match="comment()" mode="generate-id-from-path">
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
<xsl:value-of select="concat('.comment-', 1+count(preceding-sibling::comment()), '-')" />
</xsl:template>
<xsl:template match="processing-instruction()" mode="generate-id-from-path">
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
<xsl:value-of select="concat('.processing-instruction-', 1+count(preceding-sibling::processing-instruction()), '-')" />
</xsl:template>
<xsl:template match="@*" mode="generate-id-from-path">
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
<xsl:value-of select="concat('.@', name())" />
</xsl:template>
<xsl:template match="*" mode="generate-id-from-path" priority="-0.5">
<xsl:apply-templates mode="generate-id-from-path" select="parent::*" />
<xsl:text>.</xsl:text>
<xsl:value-of select="concat('.',name(),'-',1+count(preceding-sibling::*[name()=name(current())]),'-')" />
</xsl:template>
<!--MODE: GENERATE-ID-2 -->
<xsl:template match="/" mode="generate-id-2">U</xsl:template>
<xsl:template match="*" mode="generate-id-2" priority="2">
<xsl:text>U</xsl:text>
<xsl:number count="*" level="multiple" />
</xsl:template>
<xsl:template match="node()" mode="generate-id-2">
<xsl:text>U.</xsl:text>
<xsl:number count="*" level="multiple" />
<xsl:text>n</xsl:text>
<xsl:number count="node()" />
</xsl:template>
<xsl:template match="@*" mode="generate-id-2">
<xsl:text>U.</xsl:text>
<xsl:number count="*" level="multiple" />
<xsl:text>_</xsl:text>
<xsl:value-of select="string-length(local-name(.))" />
<xsl:text>_</xsl:text>
<xsl:value-of select="translate(name(),':','.')" />
</xsl:template>
<!--Strip characters--> <xsl:template match="text()" priority="-1" />
<!--SCHEMA SETUP-->
<xsl:template match="/">
<svrl:schematron-output schemaVersion="2.0.0" title="Schematron Version @xr-schematron.version.full@ - XRechnung&#xA; @xrechnung.version@ compatible - CII">
<xsl:comment>
<xsl:value-of select="$archiveDirParameter" />  
<xsl:value-of select="$archiveNameParameter" />  
<xsl:value-of select="$fileNameParameter" />  
<xsl:value-of select="$fileDirParameter" />
</xsl:comment>
<svrl:ns-prefix-in-attribute-values prefix="rsm" uri="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" />
<svrl:ns-prefix-in-attribute-values prefix="ccts" uri="urn:un:unece:uncefact:documentation:standard:CoreComponentsTechnicalSpecification:2" />
<svrl:ns-prefix-in-attribute-values prefix="udt" uri="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" />
<svrl:ns-prefix-in-attribute-values prefix="qdt" uri="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" />
<svrl:ns-prefix-in-attribute-values prefix="ram" uri="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" />
<svrl:active-pattern>
<xsl:attribute name="document">
<xsl:value-of select="document-uri(/)" />
</xsl:attribute>
<xsl:attribute name="id">CII-model</xsl:attribute>
<xsl:attribute name="name">CII-model</xsl:attribute>
<xsl:apply-templates />
</svrl:active-pattern>
<xsl:apply-templates mode="M7" select="/" />
</svrl:schematron-output>
</xsl:template>
<!--SCHEMATRON PATTERNS-->
<svrl:text>Schematron Version @xr-schematron.version.full@ - XRechnung
@xrechnung.version@ compatible - CII</svrl:text>
<!--PATTERN CII-model-->
<!--RULE -->
<xsl:template match="//rsm:CrossIndustryInvoice" mode="M7" priority="1008">
<svrl:fired-rule context="//rsm:CrossIndustryInvoice" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans" />
<xsl:otherwise>
<svrl:failed-assert test="rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans">
<xsl:attribute name="id">BR-DE-1</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-1] Eine Rechnung (INVOICE) muss Angaben zu "PAYMENT INSTRUCTIONS" (BG-16) enthalten.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="count((rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans/ram:PayeePartyCreditorFinancialAccount)[1]) + count(rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans/ram:ApplicableTradeSettlementFinancialCard) + count((rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms/ram:DirectDebitMandateID, rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:CreditorReferenceID, rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans/ram:PayerPartyDebtorFinancialAccount/ram:IBANID)[1]) = 1" />
<xsl:otherwise>
<svrl:failed-assert test="count((rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans/ram:PayeePartyCreditorFinancialAccount)[1]) + count(rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans/ram:ApplicableTradeSettlementFinancialCard) + count((rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms/ram:DirectDebitMandateID, rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:CreditorReferenceID, rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans/ram:PayerPartyDebtorFinancialAccount/ram:IBANID)[1]) = 1">
<xsl:attribute name="id">BR-DE-13</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-13] In der Rechnung müssen Angaben zu genau einer der drei Gruppen "CREDIT TRANSFER" (BG-17), "PAYMENT CARD INFORMATION" (BG-18) oder "DIRECT DEBIT" (BG-19) übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerReference[boolean(normalize-space(.))]" />
<xsl:otherwise>
<svrl:failed-assert test="rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerReference[boolean(normalize-space(.))]">
<xsl:attribute name="id">BR-DE-15</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-15] Das Element "Buyer reference" (BT-10) muss übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="(rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID='VA' or @schemeID='VAT' or @schemeID='FC'][boolean(normalize-space(.))], rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTaxRepresentativeTradeParty)" />
<xsl:otherwise>
<svrl:failed-assert test="(rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:SpecifiedTaxRegistration/ram:ID[@schemeID='VA' or @schemeID='VAT' or @schemeID='FC'][boolean(normalize-space(.))], rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTaxRepresentativeTradeParty)">
<xsl:attribute name="id">BR-DE-16</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-16] In der Rechnung muss mindestens eines der Elemente "Seller VAT identifier" (BT-31), "Seller tax registration identifier" (BT-32) oder "SELLER TAX REPRESENTATIVE PARTY" (BG-11) übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="rsm:ExchangedDocument/ram:TypeCode = ('326', '380', '384', '389', '381', '875', '876', '877')" />
<xsl:otherwise>
<svrl:failed-assert test="rsm:ExchangedDocument/ram:TypeCode = ('326', '380', '384', '389', '381', '875', '876', '877')">
<xsl:attribute name="id">BR-DE-17</xsl:attribute>
<xsl:attribute name="flag">warning</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-17] Mit dem Element "Invoice type code" (BT-3) sollen ausschließlich folgende Codes aus der Codeliste UNTDID 1001 übermittelt werden: 326 (Partial invoice), 380 (Commercial invoice), 384 (Corrected invoice), 389 (Self-billed invoice) und 381 (Credit note),875 (Partial construction invoice), 876 (Partial final construction invoice), 877 (Final construction invoice).</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="every $line in rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms/ram:Description/tokenize(.,'(\r\n|\r|\n)') satisfies if(count(tokenize($line,'#')) > 1) then tokenize($line,'#')[1]='' and (tokenize($line,'#')[2]='SKONTO' or tokenize($line,'#')[2]='VERZUG') and string-length(replace(tokenize($line,'#')[3],'TAGE=[0-9]+',''))=0 and string-length(replace(tokenize($line,'#')[4],'PROZENT=[0-9]+\.[0-9]{2}',''))=0 and (tokenize($line,'#')[5]='' and empty(tokenize($line,'#')[6]) or string-length(replace(tokenize($line,'#')[5],'BASISBETRAG=[0-9]+\.[0-9]{2}',''))=0 and tokenize($line,'#')[6]='' and empty(tokenize($line,'#')[7])) else true()" />
<xsl:otherwise>
<svrl:failed-assert test="every $line in rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms/ram:Description/tokenize(.,'(\r\n|\r|\n)') satisfies if(count(tokenize($line,'#')) > 1) then tokenize($line,'#')[1]='' and (tokenize($line,'#')[2]='SKONTO' or tokenize($line,'#')[2]='VERZUG') and string-length(replace(tokenize($line,'#')[3],'TAGE=[0-9]+',''))=0 and string-length(replace(tokenize($line,'#')[4],'PROZENT=[0-9]+\.[0-9]{2}',''))=0 and (tokenize($line,'#')[5]='' and empty(tokenize($line,'#')[6]) or string-length(replace(tokenize($line,'#')[5],'BASISBETRAG=[0-9]+\.[0-9]{2}',''))=0 and tokenize($line,'#')[6]='' and empty(tokenize($line,'#')[7])) else true()">
<xsl:attribute name="id">BR-DE-18</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-18] Die Informationen zur Gewährung von Skonto oder zur Berechnung von Verzugszinsen müssen wie folgt im Element "Payment terms" (BT-20) übermittelt werden: Anzugeben ist im ersten Segment "SKONTO" oder "VERZUG", im zweiten "TAGE=n", im dritten "PROZENT=n". Prozentzahlen sind ohne Vorzeichen sowie mit Punkt getrennt von zwei Nachkommastellen anzugeben. Liegt dem zu berechnenden Betrag nicht BT-115, "fälliger Betrag" zugrunde, sondern nur ein Teil des fälligen Betrags der Rechnung, ist der Grundwert zur Berechnung von Skonto oder Verzugszins als viertes Segment "BASISBETRAG=n" gemäß dem semantischen Datentypen Amount anzugeben. Jeder Eintrag beginnt mit einer #, die Segmente sind mit einer # getrennt und eine Zeile schließt mit einer # ab. Am Ende einer vollständigen Skonto oder Verzugsangabe muss ein XML-konformer Zeilenumbruch folgen. Alle Angaben zur Gewährung von Skonto oder zur Berechnung von Verzugszinsen müssen in Großbuchstaben gemacht werden. Zusätzliches Whitespace (Leerzeichen, Tabulatoren oder Zeilenumbrüche) ist nicht zulässig. Andere Zeichen oder Texte als in den oberen Vorgaben genannt sind nicht zulässig.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="count(//ram:AdditionalReferencedDocument) = count(//ram:AdditionalReferencedDocument[not(./ram:AttachmentBinaryObject/@filename = preceding-sibling::ram:AdditionalReferencedDocument/ram:AttachmentBinaryObject/@filename)])" />
<xsl:otherwise>
<svrl:failed-assert test="count(//ram:AdditionalReferencedDocument) = count(//ram:AdditionalReferencedDocument[not(./ram:AttachmentBinaryObject/@filename = preceding-sibling::ram:AdditionalReferencedDocument/ram:AttachmentBinaryObject/@filename)])">
<xsl:attribute name="id">BR-DE-22</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-22] Not all filename attributes of the embeddedDocumentBinaryObject elements are unique
</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates mode="M7" select="*|comment()|processing-instruction()" />
</xsl:template>
<!--RULE -->
<xsl:template match="/rsm:CrossIndustryInvoice/rsm:ExchangedDocumentContext" mode="M7" priority="1007">
<svrl:fired-rule context="/rsm:CrossIndustryInvoice/rsm:ExchangedDocumentContext" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="ram:GuidelineSpecifiedDocumentContextParameter/ram:ID = 'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0'" />
<xsl:otherwise>
<svrl:failed-assert test="ram:GuidelineSpecifiedDocumentContextParameter/ram:ID = 'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0'">
<xsl:attribute name="id">BR-DE-21</xsl:attribute>
<xsl:attribute name="flag">warning</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-21] Das Element "Specification identifier" (BT-24) soll syntaktisch der Kennung des Standards XRechnung entsprechen.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates mode="M7" select="*|comment()|processing-instruction()" />
</xsl:template>
<!--RULE -->
<xsl:template match="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty" mode="M7" priority="1006">
<svrl:fired-rule context="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="ram:DefinedTradeContact" />
<xsl:otherwise>
<svrl:failed-assert test="ram:DefinedTradeContact">
<xsl:attribute name="id">BR-DE-2</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-2] Die Gruppe "SELLER CONTACT" (BG-6) muss übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates mode="M7" select="*|comment()|processing-instruction()" />
</xsl:template>
<!--RULE -->
<xsl:template match="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:PostalTradeAddress" mode="M7" priority="1005">
<svrl:fired-rule context="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:PostalTradeAddress" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="ram:CityName[boolean(normalize-space(.))]" />
<xsl:otherwise>
<svrl:failed-assert test="ram:CityName[boolean(normalize-space(.))]">
<xsl:attribute name="id">BR-DE-3</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-3] Das Element "Seller city" (BT-37) muss übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="ram:PostcodeCode[boolean(normalize-space(.))]" />
<xsl:otherwise>
<svrl:failed-assert test="ram:PostcodeCode[boolean(normalize-space(.))]">
<xsl:attribute name="id">BR-DE-4</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-4] Das Element "Seller post code" (BT-38) muss übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates mode="M7" select="*|comment()|processing-instruction()" />
</xsl:template>
<!--RULE -->
<xsl:template match="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:DefinedTradeContact" mode="M7" priority="1004">
<svrl:fired-rule context="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:DefinedTradeContact" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="(ram:PersonName,ram:DepartmentName)[boolean(normalize-space(.))]" />
<xsl:otherwise>
<svrl:failed-assert test="(ram:PersonName,ram:DepartmentName)[boolean(normalize-space(.))]">
<xsl:attribute name="id">BR-DE-5</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-5] Das Element "Seller contact point" (BT-41) muss übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="ram:TelephoneUniversalCommunication/ram:CompleteNumber[boolean(normalize-space(.))]" />
<xsl:otherwise>
<svrl:failed-assert test="ram:TelephoneUniversalCommunication/ram:CompleteNumber[boolean(normalize-space(.))]">
<xsl:attribute name="id">BR-DE-6</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-6] Das Element "Seller contact telephone number" (BT-42) muss übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="ram:EmailURIUniversalCommunication/ram:URIID[boolean(normalize-space(.))]" />
<xsl:otherwise>
<svrl:failed-assert test="ram:EmailURIUniversalCommunication/ram:URIID[boolean(normalize-space(.))]">
<xsl:attribute name="id">BR-DE-7</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-7] Das Element "Seller contact email address" (BT-43) muss übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates mode="M7" select="*|comment()|processing-instruction()" />
</xsl:template>
<!--RULE -->
<xsl:template match="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty/ram:PostalTradeAddress" mode="M7" priority="1003">
<svrl:fired-rule context="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty/ram:PostalTradeAddress" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="ram:CityName[boolean(normalize-space(.))]" />
<xsl:otherwise>
<svrl:failed-assert test="ram:CityName[boolean(normalize-space(.))]">
<xsl:attribute name="id">BR-DE-8</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-8] Das Element "Buyer city" (BT-52) muss übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="ram:PostcodeCode[boolean(normalize-space(.))]" />
<xsl:otherwise>
<svrl:failed-assert test="ram:PostcodeCode[boolean(normalize-space(.))]">
<xsl:attribute name="id">BR-DE-9</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-9] Das Element "Buyer post code" (BT-53) muss übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates mode="M7" select="*|comment()|processing-instruction()" />
</xsl:template>
<!--RULE -->
<xsl:template match="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:PostalTradeAddress" mode="M7" priority="1002">
<svrl:fired-rule context="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:PostalTradeAddress" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="ram:CityName[boolean(normalize-space(.))]" />
<xsl:otherwise>
<svrl:failed-assert test="ram:CityName[boolean(normalize-space(.))]">
<xsl:attribute name="id">BR-DE-10</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-10] Das Element "Deliver to city" (BT-77) muss übermittelt werden, wenn die Gruppe "DELIVER TO ADDRESS" (BG-15) übermittelt wird.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="ram:PostcodeCode[boolean(normalize-space(.))]" />
<xsl:otherwise>
<svrl:failed-assert test="ram:PostcodeCode[boolean(normalize-space(.))]">
<xsl:attribute name="id">BR-DE-11</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-11] Das Element "Deliver to post code" (BT-78) muss übermittelt werden, wenn die Gruppe "DELIVER TO ADDRESS" (BG-15) übermittelt wird.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates mode="M7" select="*|comment()|processing-instruction()" />
</xsl:template>
<!--RULE -->
<xsl:template match="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans" mode="M7" priority="1001">
<svrl:fired-rule context="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="not(ram:TypeCode = '58') or matches(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')), '^[A-Z]{2}[0-9]{2}[a-zA-Z0-9]{0,30}$') and xs:integer(string-join(for $cp in string-to-codepoints(concat(substring(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),5),upper-case(substring(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),1,2)),substring(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),3,2))) return (if($cp > 64) then $cp - 55 else $cp - 48),'')) mod 97 = 1" />
<xsl:otherwise>
<svrl:failed-assert test="not(ram:TypeCode = '58') or matches(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')), '^[A-Z]{2}[0-9]{2}[a-zA-Z0-9]{0,30}$') and xs:integer(string-join(for $cp in string-to-codepoints(concat(substring(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),5),upper-case(substring(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),1,2)),substring(normalize-space(replace(ram:PayeePartyCreditorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),3,2))) return (if($cp > 64) then $cp - 55 else $cp - 48),'')) mod 97 = 1">
<xsl:attribute name="id">BR-DE-19</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-19] "Payment account identifier" (BT-84) soll eine korrekte IBAN enthalten, wenn in "Payment means type code" (BT-81) mit dem Code 58 SEPA als Zahlungsmittel gefordert wird.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<!--ASSERT -->
<xsl:choose>
<xsl:when test="not(ram:TypeCode = '59') or matches(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')), '^[A-Z]{2}[0-9]{2}[a-zA-Z0-9]{0,30}$') and xs:integer(string-join(for $cp in string-to-codepoints(concat(substring(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),5),upper-case(substring(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),1,2)),substring(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),3,2))) return (if($cp > 64) then $cp - 55 else $cp - 48),'')) mod 97 = 1" />
<xsl:otherwise>
<svrl:failed-assert test="not(ram:TypeCode = '59') or matches(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')), '^[A-Z]{2}[0-9]{2}[a-zA-Z0-9]{0,30}$') and xs:integer(string-join(for $cp in string-to-codepoints(concat(substring(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),5),upper-case(substring(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),1,2)),substring(normalize-space(replace(ram:PayerPartyDebtorFinancialAccount/ram:IBANID, '([ \n\r\t\s])', '')),3,2))) return (if($cp > 64) then $cp - 55 else $cp - 48),'')) mod 97 = 1">
<xsl:attribute name="id">BR-DE-20</xsl:attribute>
<xsl:attribute name="flag">warning</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-20] "Debited account identifier" (BT-91) soll eine korrekte IBAN enthalten, wenn in "Payment means type code" (BT-81) mit dem Code 59 SEPA als Zahlungsmittel gefordert wird.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates mode="M7" select="*|comment()|processing-instruction()" />
</xsl:template>
<!--RULE -->
<xsl:template match="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:ApplicableTradeTax" mode="M7" priority="1000">
<svrl:fired-rule context="//rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:ApplicableTradeTax" />
<!--ASSERT -->
<xsl:choose>
<xsl:when test="ram:RateApplicablePercent[boolean(normalize-space(.))]" />
<xsl:otherwise>
<svrl:failed-assert test="ram:RateApplicablePercent[boolean(normalize-space(.))]">
<xsl:attribute name="id">BR-DE-14</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates mode="schematron-select-full-path" select="." />
</xsl:attribute>
<svrl:text>[BR-DE-14] Das Element "VAT category rate" (BT-119) muss übermittelt werden.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates mode="M7" select="*|comment()|processing-instruction()" />
</xsl:template>
<xsl:template match="text()" mode="M7" priority="-1" />
<xsl:template match="@*|node()" mode="M7" priority="-2">
<xsl:apply-templates mode="M7" select="*|comment()|processing-instruction()" />
</xsl:template>
</xsl:stylesheet>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -48668,7 +48668,7 @@
<!--RULE --> <!--RULE -->
<xsl:template match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode" mode="M1452" priority="1000"> <xsl:template match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode" mode="M1452" priority="1000">
<svrl:fired-rule context="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode" /> <svrl:fired-rule context="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode" />
<xsl:variable name="codeValue5" select="." /> <xsl:variable name="codeValue5" select="@listID" />
<!--ASSERT --> <!--ASSERT -->
<xsl:choose> <xsl:choose>

File diff suppressed because it is too large Load Diff

View File

@@ -103982,7 +103982,7 @@
<!--RULE --> <!--RULE -->
<xsl:template match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode" mode="M3194" priority="1000"> <xsl:template match="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode" mode="M3194" priority="1000">
<svrl:fired-rule context="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode" /> <svrl:fired-rule context="/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedTradeProduct/ram:DesignatedProductClassification/ram:ClassCode" />
<xsl:variable name="codeValue7" select="." /> <xsl:variable name="codeValue7" select="@listID" />
<!--ASSERT --> <!--ASSERT -->
<xsl:choose> <xsl:choose>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,637 @@
<?xml version="1.0" encoding="UTF-8"?>
<codedb>
<cl id="1">
<enumeration value="80"/>
<enumeration value="81"/>
<enumeration value="82"/>
<enumeration value="83"/>
<enumeration value="84"/>
<enumeration value="130"/>
<enumeration value="202"/>
<enumeration value="203"/>
<enumeration value="204"/>
<enumeration value="211"/>
<enumeration value="261"/>
<enumeration value="262"/>
<enumeration value="295"/>
<enumeration value="296"/>
<enumeration value="308"/>
<enumeration value="325"/>
<enumeration value="326"/>
<enumeration value="380"/>
<enumeration value="381"/>
<enumeration value="383"/>
<enumeration value="384"/>
<enumeration value="385"/>
<enumeration value="386"/>
<enumeration value="387"/>
<enumeration value="388"/>
<enumeration value="389"/>
<enumeration value="390"/>
<enumeration value="393"/>
<enumeration value="394"/>
<enumeration value="395"/>
<enumeration value="396"/>
<enumeration value="420"/>
<enumeration value="456"/>
<enumeration value="457"/>
<enumeration value="458"/>
<enumeration value="527"/>
<enumeration value="575"/>
<enumeration value="623"/>
<enumeration value="633"/>
<enumeration value="751"/>
<enumeration value="780"/>
<enumeration value="935"/>
</cl>
<cl id="2">
<enumeration value="102"/>
</cl>
<cl id="3">
<enumeration value="0002"/>
<enumeration value="0003"/>
<enumeration value="0004"/>
<enumeration value="0005"/>
<enumeration value="0006"/>
<enumeration value="0007"/>
<enumeration value="0008"/>
<enumeration value="0009"/>
<enumeration value="0010"/>
<enumeration value="0011"/>
<enumeration value="0012"/>
<enumeration value="0013"/>
<enumeration value="0014"/>
<enumeration value="0015"/>
<enumeration value="0016"/>
<enumeration value="0017"/>
<enumeration value="0018"/>
<enumeration value="0019"/>
<enumeration value="0020"/>
<enumeration value="0021"/>
<enumeration value="0022"/>
<enumeration value="0023"/>
<enumeration value="0024"/>
<enumeration value="0025"/>
<enumeration value="0026"/>
<enumeration value="0027"/>
<enumeration value="0028"/>
<enumeration value="0029"/>
<enumeration value="0030"/>
<enumeration value="0031"/>
<enumeration value="0032"/>
<enumeration value="0033"/>
<enumeration value="0034"/>
<enumeration value="0035"/>
<enumeration value="0036"/>
<enumeration value="0037"/>
<enumeration value="0038"/>
<enumeration value="0039"/>
<enumeration value="0040"/>
<enumeration value="0041"/>
<enumeration value="0042"/>
<enumeration value="0043"/>
<enumeration value="0044"/>
<enumeration value="0045"/>
<enumeration value="0046"/>
<enumeration value="0047"/>
<enumeration value="0048"/>
<enumeration value="0049"/>
<enumeration value="0050"/>
<enumeration value="0051"/>
<enumeration value="0052"/>
<enumeration value="0053"/>
<enumeration value="0054"/>
<enumeration value="0055"/>
<enumeration value="0056"/>
<enumeration value="0057"/>
<enumeration value="0058"/>
<enumeration value="0059"/>
<enumeration value="0060"/>
<enumeration value="0061"/>
<enumeration value="0062"/>
<enumeration value="0063"/>
<enumeration value="0064"/>
<enumeration value="0065"/>
<enumeration value="0066"/>
<enumeration value="0067"/>
<enumeration value="0068"/>
<enumeration value="0069"/>
<enumeration value="0070"/>
<enumeration value="0071"/>
<enumeration value="0072"/>
<enumeration value="0073"/>
<enumeration value="0074"/>
<enumeration value="0075"/>
<enumeration value="0076"/>
<enumeration value="0077"/>
<enumeration value="0078"/>
<enumeration value="0079"/>
<enumeration value="0080"/>
<enumeration value="0081"/>
<enumeration value="0082"/>
<enumeration value="0083"/>
<enumeration value="0084"/>
<enumeration value="0085"/>
<enumeration value="0086"/>
<enumeration value="0087"/>
<enumeration value="0088"/>
<enumeration value="0089"/>
<enumeration value="0090"/>
<enumeration value="0091"/>
<enumeration value="0093"/>
<enumeration value="0094"/>
<enumeration value="0095"/>
<enumeration value="0096"/>
<enumeration value="0097"/>
<enumeration value="0098"/>
<enumeration value="0099"/>
<enumeration value="0100"/>
<enumeration value="0101"/>
<enumeration value="0102"/>
<enumeration value="0104"/>
<enumeration value="0105"/>
<enumeration value="0106"/>
<enumeration value="0107"/>
<enumeration value="0108"/>
<enumeration value="0109"/>
<enumeration value="0110"/>
<enumeration value="0111"/>
<enumeration value="0112"/>
<enumeration value="0113"/>
<enumeration value="0114"/>
<enumeration value="0115"/>
<enumeration value="0116"/>
<enumeration value="0117"/>
<enumeration value="0118"/>
<enumeration value="0119"/>
<enumeration value="0120"/>
<enumeration value="0121"/>
<enumeration value="0122"/>
<enumeration value="0123"/>
<enumeration value="0124"/>
<enumeration value="0125"/>
<enumeration value="0126"/>
<enumeration value="0127"/>
<enumeration value="0128"/>
<enumeration value="0129"/>
<enumeration value="0130"/>
<enumeration value="0131"/>
<enumeration value="0132"/>
<enumeration value="0133"/>
<enumeration value="0134"/>
<enumeration value="0135"/>
<enumeration value="0136"/>
<enumeration value="0137"/>
<enumeration value="0138"/>
<enumeration value="0139"/>
<enumeration value="0140"/>
<enumeration value="0141"/>
<enumeration value="0142"/>
<enumeration value="0143"/>
<enumeration value="0144"/>
<enumeration value="0145"/>
<enumeration value="0146"/>
<enumeration value="0147"/>
<enumeration value="0148"/>
<enumeration value="0149"/>
<enumeration value="0150"/>
<enumeration value="0151"/>
<enumeration value="0152"/>
<enumeration value="0153"/>
<enumeration value="0154"/>
<enumeration value="0155"/>
<enumeration value="0156"/>
<enumeration value="0157"/>
<enumeration value="0158"/>
<enumeration value="0159"/>
<enumeration value="0160"/>
<enumeration value="0161"/>
<enumeration value="0162"/>
<enumeration value="0163"/>
<enumeration value="0164"/>
<enumeration value="0165"/>
<enumeration value="0166"/>
<enumeration value="0167"/>
<enumeration value="0168"/>
<enumeration value="0169"/>
<enumeration value="0170"/>
<enumeration value="0171"/>
<enumeration value="0172"/>
<enumeration value="0173"/>
<enumeration value="0174"/>
<enumeration value="0175"/>
<enumeration value="0176"/>
<enumeration value="0177"/>
<enumeration value="0178"/>
<enumeration value="0179"/>
<enumeration value="0180"/>
<enumeration value="0183"/>
<enumeration value="0184"/>
<enumeration value="0185"/>
<enumeration value="0186"/>
<enumeration value="0187"/>
<enumeration value="0188"/>
<enumeration value="0189"/>
<enumeration value="0190"/>
<enumeration value="0191"/>
<enumeration value="0192"/>
<enumeration value="0193"/>
<enumeration value="0194"/>
<enumeration value="0195"/>
<enumeration value="0196"/>
<enumeration value="0197"/>
<enumeration value="0198"/>
<enumeration value="0199"/>
<enumeration value="0200"/>
<enumeration value="0201"/>
<enumeration value="0202"/>
<enumeration value="0203"/>
<enumeration value="0204"/>
</cl>
<cl id="4">
<enumeration value="FC"/>
<enumeration value="VA"/>
</cl>
<cl id="5">
<enumeration value="0002"/>
<enumeration value="0003"/>
<enumeration value="0004"/>
<enumeration value="0005"/>
<enumeration value="0006"/>
<enumeration value="0007"/>
<enumeration value="0008"/>
<enumeration value="0009"/>
<enumeration value="0010"/>
<enumeration value="0011"/>
<enumeration value="0012"/>
<enumeration value="0013"/>
<enumeration value="0014"/>
<enumeration value="0015"/>
<enumeration value="0016"/>
<enumeration value="0017"/>
<enumeration value="0018"/>
<enumeration value="0019"/>
<enumeration value="0020"/>
<enumeration value="0021"/>
<enumeration value="0022"/>
<enumeration value="0023"/>
<enumeration value="0024"/>
<enumeration value="0025"/>
<enumeration value="0026"/>
<enumeration value="0027"/>
<enumeration value="0028"/>
<enumeration value="0029"/>
<enumeration value="0030"/>
<enumeration value="0031"/>
<enumeration value="0032"/>
<enumeration value="0033"/>
<enumeration value="0034"/>
<enumeration value="0035"/>
<enumeration value="0036"/>
<enumeration value="0037"/>
<enumeration value="0038"/>
<enumeration value="0039"/>
<enumeration value="0040"/>
<enumeration value="0041"/>
<enumeration value="0042"/>
<enumeration value="0043"/>
<enumeration value="0044"/>
<enumeration value="0045"/>
<enumeration value="0046"/>
<enumeration value="0047"/>
<enumeration value="0048"/>
<enumeration value="0049"/>
<enumeration value="0050"/>
<enumeration value="0051"/>
<enumeration value="0052"/>
<enumeration value="0053"/>
<enumeration value="0054"/>
<enumeration value="0055"/>
<enumeration value="0056"/>
<enumeration value="0057"/>
<enumeration value="0058"/>
<enumeration value="0059"/>
<enumeration value="0060"/>
<enumeration value="0061"/>
<enumeration value="0062"/>
<enumeration value="0063"/>
<enumeration value="0064"/>
<enumeration value="0065"/>
<enumeration value="0066"/>
<enumeration value="0067"/>
<enumeration value="0068"/>
<enumeration value="0069"/>
<enumeration value="0070"/>
<enumeration value="0071"/>
<enumeration value="0072"/>
<enumeration value="0073"/>
<enumeration value="0074"/>
<enumeration value="0075"/>
<enumeration value="0076"/>
<enumeration value="0077"/>
<enumeration value="0078"/>
<enumeration value="0079"/>
<enumeration value="0080"/>
<enumeration value="0081"/>
<enumeration value="0082"/>
<enumeration value="0083"/>
<enumeration value="0084"/>
<enumeration value="0085"/>
<enumeration value="0086"/>
<enumeration value="0087"/>
<enumeration value="0088"/>
<enumeration value="0089"/>
<enumeration value="0090"/>
<enumeration value="0091"/>
<enumeration value="0093"/>
<enumeration value="0094"/>
<enumeration value="0095"/>
<enumeration value="0096"/>
<enumeration value="0097"/>
<enumeration value="0098"/>
<enumeration value="0099"/>
<enumeration value="0100"/>
<enumeration value="0101"/>
<enumeration value="0102"/>
<enumeration value="0104"/>
<enumeration value="0105"/>
<enumeration value="0106"/>
<enumeration value="0107"/>
<enumeration value="0108"/>
<enumeration value="0109"/>
<enumeration value="0110"/>
<enumeration value="0111"/>
<enumeration value="0112"/>
<enumeration value="0113"/>
<enumeration value="0114"/>
<enumeration value="0115"/>
<enumeration value="0116"/>
<enumeration value="0117"/>
<enumeration value="0118"/>
<enumeration value="0119"/>
<enumeration value="0120"/>
<enumeration value="0121"/>
<enumeration value="0122"/>
<enumeration value="0123"/>
<enumeration value="0124"/>
<enumeration value="0125"/>
<enumeration value="0126"/>
<enumeration value="0127"/>
<enumeration value="0128"/>
<enumeration value="0129"/>
<enumeration value="0130"/>
<enumeration value="0131"/>
<enumeration value="0132"/>
<enumeration value="0133"/>
<enumeration value="0134"/>
<enumeration value="0135"/>
<enumeration value="0136"/>
<enumeration value="0137"/>
<enumeration value="0138"/>
<enumeration value="0139"/>
<enumeration value="0140"/>
<enumeration value="0141"/>
<enumeration value="0142"/>
<enumeration value="0143"/>
<enumeration value="0144"/>
<enumeration value="0145"/>
<enumeration value="0146"/>
<enumeration value="0147"/>
<enumeration value="0148"/>
<enumeration value="0149"/>
<enumeration value="0150"/>
<enumeration value="0151"/>
<enumeration value="0152"/>
<enumeration value="0153"/>
<enumeration value="0154"/>
<enumeration value="0155"/>
<enumeration value="0156"/>
<enumeration value="0157"/>
<enumeration value="0158"/>
<enumeration value="0159"/>
<enumeration value="0160"/>
<enumeration value="0161"/>
<enumeration value="0162"/>
<enumeration value="0163"/>
<enumeration value="0164"/>
<enumeration value="0165"/>
<enumeration value="0166"/>
<enumeration value="0167"/>
<enumeration value="0168"/>
<enumeration value="0169"/>
<enumeration value="0170"/>
<enumeration value="0171"/>
<enumeration value="0172"/>
<enumeration value="0173"/>
<enumeration value="0174"/>
<enumeration value="0175"/>
<enumeration value="0176"/>
<enumeration value="0177"/>
<enumeration value="0178"/>
<enumeration value="0179"/>
<enumeration value="0180"/>
<enumeration value="0183"/>
<enumeration value="0184"/>
<enumeration value="0185"/>
<enumeration value="0186"/>
<enumeration value="0187"/>
<enumeration value="0188"/>
<enumeration value="0189"/>
<enumeration value="0190"/>
<enumeration value="0191"/>
<enumeration value="0192"/>
<enumeration value="0193"/>
<enumeration value="0194"/>
<enumeration value="0195"/>
<enumeration value="0196"/>
<enumeration value="0197"/>
<enumeration value="0198"/>
<enumeration value="0199"/>
<enumeration value="0200"/>
<enumeration value="0201"/>
<enumeration value="0202"/>
<enumeration value="0203"/>
<enumeration value="0204"/>
</cl>
<cl id="6">
<enumeration value="AED"/>
<enumeration value="AFN"/>
<enumeration value="ALL"/>
<enumeration value="AMD"/>
<enumeration value="ANG"/>
<enumeration value="AOA"/>
<enumeration value="ARS"/>
<enumeration value="AUD"/>
<enumeration value="AWG"/>
<enumeration value="AZN"/>
<enumeration value="BAM"/>
<enumeration value="BBD"/>
<enumeration value="BDT"/>
<enumeration value="BGN"/>
<enumeration value="BHD"/>
<enumeration value="BIF"/>
<enumeration value="BMD"/>
<enumeration value="BND"/>
<enumeration value="BOB"/>
<enumeration value="BOV"/>
<enumeration value="BRL"/>
<enumeration value="BSD"/>
<enumeration value="BTN"/>
<enumeration value="BWP"/>
<enumeration value="BYN"/>
<enumeration value="BZD"/>
<enumeration value="CAD"/>
<enumeration value="CDF"/>
<enumeration value="CHE"/>
<enumeration value="CHF"/>
<enumeration value="CHW"/>
<enumeration value="CLF"/>
<enumeration value="CLP"/>
<enumeration value="CNY"/>
<enumeration value="COP"/>
<enumeration value="COU"/>
<enumeration value="CRC"/>
<enumeration value="CUC"/>
<enumeration value="CUP"/>
<enumeration value="CVE"/>
<enumeration value="CZK"/>
<enumeration value="DJF"/>
<enumeration value="DKK"/>
<enumeration value="DOP"/>
<enumeration value="DZD"/>
<enumeration value="EGP"/>
<enumeration value="ERN"/>
<enumeration value="ETB"/>
<enumeration value="EUR"/>
<enumeration value="FJD"/>
<enumeration value="FKP"/>
<enumeration value="GBP"/>
<enumeration value="GEL"/>
<enumeration value="GHS"/>
<enumeration value="GIP"/>
<enumeration value="GMD"/>
<enumeration value="GNF"/>
<enumeration value="GTQ"/>
<enumeration value="GYD"/>
<enumeration value="HKD"/>
<enumeration value="HNL"/>
<enumeration value="HRK"/>
<enumeration value="HTG"/>
<enumeration value="HUF"/>
<enumeration value="IDR"/>
<enumeration value="ILS"/>
<enumeration value="INR"/>
<enumeration value="IQD"/>
<enumeration value="IRR"/>
<enumeration value="ISK"/>
<enumeration value="JMD"/>
<enumeration value="JOD"/>
<enumeration value="JPY"/>
<enumeration value="KES"/>
<enumeration value="KGS"/>
<enumeration value="KHR"/>
<enumeration value="KMF"/>
<enumeration value="KPW"/>
<enumeration value="KRW"/>
<enumeration value="KWD"/>
<enumeration value="KYD"/>
<enumeration value="KZT"/>
<enumeration value="LAK"/>
<enumeration value="LBP"/>
<enumeration value="LKR"/>
<enumeration value="LRD"/>
<enumeration value="LSL"/>
<enumeration value="LYD"/>
<enumeration value="MAD"/>
<enumeration value="MDL"/>
<enumeration value="MGA"/>
<enumeration value="MKD"/>
<enumeration value="MMK"/>
<enumeration value="MNT"/>
<enumeration value="MOP"/>
<enumeration value="MRU"/>
<enumeration value="MUR"/>
<enumeration value="MVR"/>
<enumeration value="MWK"/>
<enumeration value="MXN"/>
<enumeration value="MXV"/>
<enumeration value="MYR"/>
<enumeration value="MZN"/>
<enumeration value="NAD"/>
<enumeration value="NGN"/>
<enumeration value="NIO"/>
<enumeration value="NOK"/>
<enumeration value="NPR"/>
<enumeration value="NZD"/>
<enumeration value="OMR"/>
<enumeration value="PAB"/>
<enumeration value="PEN"/>
<enumeration value="PGK"/>
<enumeration value="PHP"/>
<enumeration value="PKR"/>
<enumeration value="PLN"/>
<enumeration value="PYG"/>
<enumeration value="QAR"/>
<enumeration value="RON"/>
<enumeration value="RSD"/>
<enumeration value="RUB"/>
<enumeration value="RWF"/>
<enumeration value="SAR"/>
<enumeration value="SBD"/>
<enumeration value="SCR"/>
<enumeration value="SDG"/>
<enumeration value="SEK"/>
<enumeration value="SGD"/>
<enumeration value="SHP"/>
<enumeration value="SLL"/>
<enumeration value="SOS"/>
<enumeration value="SRD"/>
<enumeration value="SSP"/>
<enumeration value="STN"/>
<enumeration value="SVC"/>
<enumeration value="SYP"/>
<enumeration value="SZL"/>
<enumeration value="THB"/>
<enumeration value="TJS"/>
<enumeration value="TMT"/>
<enumeration value="TND"/>
<enumeration value="TOP"/>
<enumeration value="TRY"/>
<enumeration value="TTD"/>
<enumeration value="TWD"/>
<enumeration value="TZS"/>
<enumeration value="UAH"/>
<enumeration value="UGX"/>
<enumeration value="USD"/>
<enumeration value="USN"/>
<enumeration value="UYI"/>
<enumeration value="UYU"/>
<enumeration value="UYW"/>
<enumeration value="UZS"/>
<enumeration value="VES"/>
<enumeration value="VND"/>
<enumeration value="VUV"/>
<enumeration value="WST"/>
<enumeration value="XAF"/>
<enumeration value="XAG"/>
<enumeration value="XAU"/>
<enumeration value="XBA"/>
<enumeration value="XBB"/>
<enumeration value="XBC"/>
<enumeration value="XBD"/>
<enumeration value="XCD"/>
<enumeration value="XDR"/>
<enumeration value="XOF"/>
<enumeration value="XPD"/>
<enumeration value="XPF"/>
<enumeration value="XPT"/>
<enumeration value="XSU"/>
<enumeration value="XTS"/>
<enumeration value="XUA"/>
<enumeration value="XXX"/>
<enumeration value="YER"/>
<enumeration value="ZAR"/>
<enumeration value="ZMW"/>
<enumeration value="ZWL"/>
</cl>
</codedb>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet version="2.0" xmlns:ccts="urn:un:unece:uncefact:documentation:standard:CoreComponentsTechnicalSpecification:2" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:12" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12" xmlns:rsm="urn:ferd:CrossIndustryDocument:invoice:1p0" xmlns:schold="http://www.ascc.net/xml/schematron" xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:stylesheet xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:ccts="urn:un:unece:uncefact:documentation:standard:CoreComponentsTechnicalSpecification:2" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:12" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12" xmlns:rsm="urn:ferd:CrossIndustryDocument:invoice:1p0" xmlns:schold="http://www.ascc.net/xml/schematron" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<!--Implementers: please note that overriding process-prolog or process-root is <!--Implementers: please note that overriding process-prolog or process-root is
the preferred method for meta-stylesheets to use where possible. --> the preferred method for meta-stylesheets to use where possible. -->

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More