Merge branch 'mustang-master' into forked-master

This commit is contained in:
Sebastian Sieber
2024-07-30 08:46:09 +02:00
149 changed files with 50064 additions and 19410 deletions

View File

@@ -16,7 +16,7 @@ jobs:
- uses: actions/setup-java@v3 # the log states the default ~/.m2/toolchains.xml is being created pointing to the JDK
with:
distribution: 'adopt' # for latest JDKs use temurin https://blog.adoptopenjdk.net/2021/08/goodbye-adoptopenjdk-hello-adoptium/
java-version: '8'
java-version: '11'
cache: 'maven' #cache/restore any dependencies to improve the workflow execution time
- name: Build with Maven
run: mvn -B package --file pom.xml

View File

@@ -1,3 +1,43 @@
2.12.0
=======
2024-07-20
- support pdf export/visualization to PDF, thanks to Heavenfighter #387 allow embedd fonts from jar-file for pdf creation #388
- Fix #389: ClassCastException: ZUGFeRDExporterFromA3
- jakarta support #372
- Upgrade to PDFBox 3 #373
- Requires Java 11
- #397 Build succeeds but file is unusable on alpine/docker
- #392 CLI: action combine: --ignorefileextension to ignore PDF/A input file errors dosen't work
- for CLI combine, fx is now default
- set profile to XR if XR is imported #395
- Powershell compatibility: added --no-additional-attachments command line option for better batch processing:
In cmd also --attachments "" worked but in powershell it was hard to figure out that one had to use --attachments '""'
- Be able to validate XRechnung/UBL files #337
- ph-schematron aktualisiert, logback zugungsten log4j entfernt #402
- java.util Logging zugungsten log4j entfernt #407
- ZF extended no longer requires deliverydate #411
- Return all BankDetails from parsed CII xml. Closes #408.
- ubl visualization: do not require ubl namespace prefix #416
2.11.0
=======
2024-05-22
- EN16931 validation 1.3.12 codelists v11 #357
- Fonts removed #358
- xrechnungimporter to read from filename, inputstream
- invoice's getSender/getRecipient() now return tradeparty no IZUGFeRDExportableTradeParty
- (first) IBAN is now parsed into sender's getBankDetails
- zugferdimporter to accept xml files
- UBL importer to also parse contacts
- https://github.com/ZUGFeRD/mustangproject/pull/369
- support inputstreams https://github.com/ZUGFeRD/mustangproject/pull/379
- #314 ZUGFeRDInvoiceImporter additional constructur
- add XML cash discount write support (new class, previously only possible for XRechnung, not ZF Extended, using a manually encoded setPaymentTermDescription)
- surrendered to XRechnung 3 compromises, e.g. no longer put gross amount if it does not deviate from net
- be able to programmatically access validation messages https://github.com/ZUGFeRD/mustangproject/pull/382
2.10.0
=======
2023-12-30

View File

@@ -1,258 +1,244 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<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">
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.12.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.9.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>Mustang-CLI</artifactId>
<name>e-invoices commandline tool, allowing to create(embed), split and validate Factur-X/ZUGFeRD files. Validation should also work for XRechnung/CII. </name>
<packaging>jar</packaging>
<version>2.9.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.compilerVersion>8</maven.compiler.compilerVersion>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>validator</artifactId>
<version>2.9.1-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
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
-->
</dependency>
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
<dependency><!-- apache commons cli to parse command line -->
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.5.0</version>
</dependency>
<artifactId>Mustang-CLI</artifactId>
<name>e-invoices commandline tool, allowing to create(embed), split and validate Factur-X/ZUGFeRD files. Validation
should also work for XRechnung/CII.
</name>
<packaging>jar</packaging>
<version>2.12.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.compilerVersion>11</maven.compiler.compilerVersion>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>validator</artifactId>
<version>2.12.0-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
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
-->
</dependency>
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
<dependency><!-- apache commons cli to parse command line -->
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.riversun</groupId>
<artifactId>bigdoc</artifactId>
<version>0.3.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
<!-- for directory validation: -->
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-assertj</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<!-- for directory validation: -->
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-assertj</artifactId>
<version>2.10.0</version>
</dependency>
<!-- /directory validation: -->
<!-- /directory validation: -->
</dependencies>
<build>
<pluginManagement>
<plugins>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.2</version>
</dependency>
</dependencies>
<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>
</plugin>
</plugins>
</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>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
<!-- allow getImplementationVersion for the pom.xml -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
<manifestSections>
<manifestSection>
<name>FreeSans.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>FreeSerif.ttf</name>
<manifestEntries>
<Content-Type>application/x-font</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>Times-Bold.ttf</name>
<manifestEntries>
<Content-Type>application/x-font</Content-Type>
</manifestEntries>
</manifestSection>
</manifestSections>
<!-- allow getImplementationVersion for the pom.xml -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>org.mustangproject.commandline.main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
mvn clean compile assembly:single -->
<!-- or whatever version you use -->
<source>8</source>
<target>8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.mustangproject.commandline.Main</mainClass>
</transformer>
</transformers>
<minimizeJar>false</minimizeJar>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>LICENSE</exclude>
<exclude>NOTICE</exclude>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
<filter>
<artifact>log4j:log4j</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>commons-logging:commons-logging</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>com.sun.xml.bind:jaxb-impl</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes />
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile> <!-- enforce building binaries with Java 1.8 for Maven Central, otherwise using them e.g. as jar will
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>org.mustangproject.commandline.main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
mvn clean compile assembly:single -->
<!-- or whatever version you use -->
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.mustangproject.commandline.Main</mainClass>
</transformer>
</transformers>
<minimizeJar>false</minimizeJar>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>LICENSE</exclude>
<exclude>NOTICE</exclude>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
<filter>
<artifact>log4j:log4j</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>commons-logging:commons-logging</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>com.sun.xml.bind:jaxb-impl</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes/>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile> <!-- enforce building binaries with Java 1.8 for Maven Central, otherwise using them e.g. as jar will
throw a version exception, triggered automatically on mvn release:release (hopefully) and requires an according
~/.m2/toolchains.xml file, @see doc/development_documentation.md -->
<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-toolchains-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>8</version>
<vendor>adopt</vendor>
</jdk>
</toolchains>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
<comments>A business-friendly OSS license</comments>
</license>
</licenses>
<developers>
<developer>
<name>Jochen Stärk</name>
<email>jstaerk@usegroup.de</email>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
</developer>
</developers>
<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-toolchains-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>11</version>
<vendor>adopt</vendor>
</jdk>
</toolchains>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
<comments>A business-friendly OSS license</comments>
</license>
</licenses>
<developers>
<developer>
<name>Jochen Stärk</name>
<email>jstaerk@usegroup.de</email>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
</developer>
</developers>
</project>

View File

@@ -36,64 +36,66 @@ import java.util.ArrayList;
public class Main {
private static org.slf4j.Logger LOGGER; // log output
private static void printUsage() {
System.err.println(getUsage());
}
private static String getUsage() {
return "Usage: --action metrics|combine|extract|a3only|ubl|validate|validateExpectInvalid|validateExpectValid|visualize [-d,--directory] [-l,--listfromstdin] [-i,--ignore fileextension, PDF/A errors] [--disable-file-logging] | [-h,--help] \r\n"
+ " --action license display open source license and notice\n"
+ " --action metrics\n"
+ " -d, --directory count ZUGFeRD files in directory to be scanned\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"
+ " It will start once a blank line has been entered.\n" + "\n"
+ " Additional parameter for both count operations\n"
+ " [-i, --ignorefileextension] Check for all files (*.*) instead of PDF files only (*.pdf) in metrics, ignore PDF/A input file errors in combine\n"
+ " [--disable-file-logging] disable logging to file.\n"
+ " --action extract extract Factur-X PDF to XML file\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n"
+ " [--out <filename>]: set output XML file\n"
+ " --action a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n"
+ " [--out <filename>]: set output PDF file\n"
+ " --action combine combine XML and PDF file to Factur-X PDF file\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n"
+ " [--source-xml <filename>]: set input XML file\n"
+ " [--out <filename>]: set output PDF file\n"
+ " [--format <fx|zf|ox|da>]: set Factur-X, ZUGFeRD, Order-X or Cross Industry Despatch Advice\n"
+ " [--version <1|2>]: set ZUGFeRD version\n"
+ " [--profile <...>]: set ZUGFeRD profile\n"
+ " For ZUGFeRD v1 or Order-X: <B>ASIC, <C>OMFORT or EX<T>ENDED\n"
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, <X>Rechnung, EX<T>ENDED\n"
+ " [--attachments <filenames>]: list of file attachments (passing a single empty file name prevents prompting)\n"
+ " --action ubl convert UN/CEFACT 2016b CII XML to UBL XML\n"
+ " [--source <filename>]: set input XML file\n"
+ " [--out <filename>]: set output XML file\n"
+ " --action upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input XML ZUGFeRD 1 file\n"
+ " [--out <filename>]: set output XML ZUGFeRD 2 file\n"
+ " --action 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"
+ " [--source <filename>]: input PDF or XML file\n"
+ " --action 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"
+ " --action 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"
+ " --action visualize convert XML to HTML \n"
+ " [--language <lang>]: set output lang (en, fr or de)\n"
+ " [--source <filename>]: set input XML file\n"
+ " [--out <filename>]: set output HTML file\n"
+ " --action license display open source license and notice\n"
+ " --action metrics\n"
+ " -d, --directory count ZUGFeRD files in directory to be scanned\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"
+ " It will start once a blank line has been entered.\n" + "\n"
+ " Additional parameter for both count operations\n"
+ " [-i, --ignorefileextension] Check for all files (*.*) instead of PDF files only (*.pdf) in metrics, ignore PDF/A input file errors in combine\n"
+ " [--disable-file-logging] disable logging to file.\n"
+ " --action extract extract Factur-X PDF to XML file\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n"
+ " [--out <filename>]: set output XML file\n"
+ " --action a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n"
+ " [--out <filename>]: set output PDF file\n"
+ " --action combine combine XML and PDF file to Factur-X PDF file\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n"
+ " [--source-xml <filename>]: set input XML file\n"
+ " [--out <filename>]: set output PDF file\n"
+ " [--format <fx|zf|ox|da>]: set Factur-X, ZUGFeRD, Order-X or Cross Industry Despatch Advice\n"
+ " [--version <1|2>]: set ZUGFeRD version\n"
+ " [--profile <...>]: set ZUGFeRD profile\n"
+ " For ZUGFeRD v1 or Order-X: <B>ASIC, <C>OMFORT or EX<T>ENDED\n"
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, <X>Rechnung, EX<T>ENDED\n"
+ " [--attachments <filenames>]: list of file attachments (passing a single empty file name prevents prompting)\n"
+ " [--no-additional-attachments]: prevent prompting for attachments\n"
+ " --action ubl convert UN/CEFACT 2016b CII XML to UBL XML\n"
+ " [--source <filename>]: set input XML file\n"
+ " [--out <filename>]: set output XML file\n"
+ " --action upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input XML ZUGFeRD 1 file\n"
+ " [--out <filename>]: set output XML ZUGFeRD 2 file\n"
+ " --action 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"
+ " [--source <filename>]: input PDF or XML file\n"
+ " --action 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"
+ " --action 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"
+ " --action visualize convert XML to HTML \n"
+ " [--language <lang>]: set output lang (en, fr or de)\n"
+ " [--source <filename>]: set input XML file\n"
+ " [--out <filename>]: set output HTML file\n"
+ " --action pdf convert XML to PDF \n"
+ " [--source <filename>]: set input XML file\n"
+ " [--out <filename>]: set output PDF file\n"
@@ -330,32 +332,36 @@ public class Main {
public static void main(String[] args) {
try {
CommandLine cmd;
CommandLineParser parser = new BasicParser();
CommandLineParser parser = new DefaultParser();
// create Options object
Options options = new Options();
options.addOption(new Option("h", "help", false, "display usage"));
options.addOption(new Option("a", "action", true, "which action to perform"));
options.addOption(new Option("f", "format", true, "which format to output"));
options.addOption(new Option("", "version", true, "which version of the standard to use"));
options.addOption(new Option("", "profile", true, "which profile of the standard to use"));
Option attachmentOpt = new Option("", "attachments", true, "File attachments");
options.addOption(new Option("version", "version", true, "which version of the standard to use"));
options.addOption(new Option("profile", "profile", true, "which profile of the standard to use"));
options.addOption(new Option("no-additional-attachments", "no-additional-attachments", false, "prevent prompting for attachments"));
Option attachmentOpt = new Option("attachments", "attachments", true, "File attachments");
attachmentOpt.setValueSeparator(',');
attachmentOpt.setArgs(Option.UNLIMITED_VALUES);
options.addOption(attachmentOpt);
options.addOption(new Option("", "source",true, "which source file to use"));
options.addOption(new Option("", "source-xml",true, "which source file to use"));
options.addOption(new Option("", "language",true, "output language (en, de or fr)"));
options.addOption(new Option("", "out",true, "which output file to write to"));
options.addOption(new Option("", "no-notices",false, "suppress non-fatal errors"));
options.addOption(new Option("", "logAppend",true, "freeform text to be appended to log messages"));
options.addOption(new Option("", "disable-file-logging", false, "suppress logging to file"));
options.addOption(new Option("d", "directory",true, "which directory to operate on"));
options.addOption(new Option("i", "ignorefileextension",false, "ignore non-matching file extensions"));
options.addOption(new Option("l", "listfromstdin",false, "take list of files from commandline"));
boolean optionsRecognized=false;
options.addOption(new Option("source", "source", true, "which source file to use"));
options.addOption(new Option("source-xml", "source-xml", true, "which source file to use"));
options.addOption(new Option("language", "language", true, "output language (en, de or fr)"));
options.addOption(new Option("out", "out", true, "which output file to write to"));
options.addOption(new Option("no-notices", "no-notices", false, "suppress non-fatal errors"));
options.addOption(new Option("logAppend", "logAppend", true, "freeform text to be appended to log messages"));
options.addOption(new Option("disable-file-logging", "disable-file-logging", false, "suppress logging to file"));
options.addOption(new Option("d", "directory", true, "which directory to operate on"));
options.addOption(new Option("i", "ignorefileextension", false, "ignore non-matching file extensions"));
options.addOption(new Option("l", "listfromstdin", false, "take list of files from commandline"));
boolean optionsRecognized = false;
String action = "";
Boolean disableFileLogging = false;
Boolean disableFileLogging = false;
try {
cmd = parser.parse(options, args);
@@ -364,7 +370,8 @@ public class Main {
String directoryName = cmd.getOptionValue("directory");
Boolean filesFromStdIn = cmd.hasOption("listfromstdin");//((Number)cmdLine.getParsedOptionValue("integer-option")).intValue();
Boolean ignoreFileExt = cmd.hasOption("ignorefileextension");
Boolean helpRequested = cmd.hasOption("help") || ((action!=null)&&(action.equals("help")));
Boolean noAttachments = cmd.hasOption("no-additional-attachments");
Boolean helpRequested = cmd.hasOption("help") || ((action != null) && (action.equals("help")));
disableFileLogging = cmd.hasOption("disable-file-logging");
String sourceName = cmd.getOptionValue("source");
@@ -380,14 +387,12 @@ public class Main {
String[] attachmentFilenames = cmd.hasOption("attachments") ? cmd.getOptionValues("attachments") : null;
ArrayList<FileAttachment> attachments=new ArrayList <>();
ArrayList<FileAttachment> attachments = new ArrayList<>();
/*
setting system property to disable FILE appender and
suppress creation of files and folders.
*/
System.setProperty("FILE_APPENDER_ENABLED", ((Boolean)(disableFileLogging==false)).toString());
System.setProperty("FILE_APPENDER_ENABLED", ((Boolean) (disableFileLogging == false)).toString());
LOGGER = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
@@ -401,7 +406,7 @@ public class Main {
performMetrics(directoryName, filesFromStdIn, ignoreFileExt);
optionsRecognized = true;
} else if ((action != null) && (action.equals("combine"))) {
performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile, ignoreFileExt, attachmentFilenames, attachments);
performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile, ignoreFileExt, attachmentFilenames, attachments, noAttachments);
optionsRecognized = true;
} else if ((action != null) && (action.equals("extract"))) {
performExtract(sourceName, outName);
@@ -422,7 +427,7 @@ public class Main {
performUBL(sourceName, outName);
optionsRecognized = true;
} else if ((action != null) && (action.equals("validate"))) {
optionsRecognized = performValidate(sourceName, noNotices != null && noNotices, cmd.getOptionValue("logAppend"));
optionsRecognized = performValidate(sourceName, noNotices, cmd.getOptionValue("logAppend"));
} else if ((action != null) && (action.equals("validateExpectValid"))) {
optionsRecognized = performValidateExpect(true, directoryName);
} else if ((action != null) && (action.equals("validateExpectInvalid"))) {
@@ -439,7 +444,11 @@ public class Main {
System.exit(2);
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
if (LOGGER != null) {
LOGGER.error(e.getMessage(), e);
} else {
System.err.println(e.getMessage());
}
System.exit(-1);
}
@@ -510,10 +519,11 @@ public class Main {
ensureFileNotExists(outName);
// All params are good! continue...
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().convertOnly().load(pdfName);
ze.export(outName);
System.out.println("Written to " + outName);
try (ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1()) {
ze.convertOnly().load(pdfName);
ze.export(outName);
System.out.println("Written to " + outName);
}
}
private static void performExtract(String pdfName, String xmlName) throws IOException {
@@ -546,7 +556,7 @@ public class Main {
}
private static void performCombine(String pdfName, String xmlName, String outName, String format, String zfVersion,
String zfProfile, Boolean ignoreInputErrors, String[] attachmentFilenames, ArrayList<FileAttachment> attachments) throws Exception {
String zfProfile, Boolean ignoreInputErrors, String[] attachmentFilenames, ArrayList<FileAttachment> attachments, Boolean noAttachments) throws Exception {
/*
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
* .setProducer("toecount") .setCreator(System.getProperty("user.name"))
@@ -576,12 +586,14 @@ public class Main {
if (attachmentFilenames == null) {
byte attachmentContents[] = null;
String attachmentFilename, attachmentMime, attachmentDescription;
attachmentFilename = getFilenameFromUser("Additional file attachments filename (empty for none)", "", "pdf", true, false);
if (attachmentFilename.length() != 0) {
attachmentContents = Files.readAllBytes(Paths.get(attachmentFilename));
attachmentMime = Files.probeContentType(Paths.get(attachmentFilename));
attachments.add(new FileAttachment(attachmentFilename, attachmentMime, "Data", attachmentContents));
String attachmentFilename, attachmentMime;
if (!noAttachments) {
attachmentFilename = getFilenameFromUser("Additional file attachments filename (empty for none)", "", "pdf", true, false);
if (attachmentFilename.length() != 0) {
attachmentContents = Files.readAllBytes(Paths.get(attachmentFilename));
attachmentMime = Files.probeContentType(Paths.get(attachmentFilename));
attachments.add(new FileAttachment(attachmentFilename, attachmentMime, "Data", attachmentContents));
}
}
} else {
for (int i = 0; i < attachmentFilenames.length; i++) {
@@ -597,7 +609,7 @@ public class Main {
if (format == null) {
try {
format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD, ox=Order-X, da=Cross Industry Despatch Advice)", "zf", "fx|zf|ox|da");
format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD, ox=Order-X, da=Cross Industry Despatch Advice)", "fx", "fx|zf|ox|da");
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
@@ -607,7 +619,7 @@ public class Main {
if (zfVersion == null) {
try {
zfVersion = getStringFromUser("Version (1 or 2)", Integer.toString(ZUGFeRDExporterFromA3.DefaultZUGFeRDVersion), "1|2");
zfVersion = getStringFromUser("Version (1 or 2)", "1", "1|2");//fx default version is 1
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
@@ -691,41 +703,33 @@ public class Main {
IZUGFeRDExporter ze = null;
// All params are good! continue...
if (format.equals("ox")) {
ze = new OXExporterFromA1().setProducer("Mustang-cli")
.setZUGFeRDVersion(zfIntVersion)
.setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile);
ze = new OXExporterFromA1();
if (ignoreInputErrors) {
((OXExporterFromA1) ze).ignorePDFAErrors();
}
} else if (format.equals("da")) {
ze = new DXExporterFromA1().setProducer("Mustang-cli")
.setZUGFeRDVersion(zfIntVersion)
.setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile);
ze = new DXExporterFromA1();
if (ignoreInputErrors) {
((DXExporterFromA1) ze).ignorePDFAErrors();
}
} else {
if (format.equals("fx")) {
zfIntVersion=2;// actually we are talking of generation, not version
zfIntVersion = 2;// actually we are talking of generation, not version
// so even if someone correctly requested factur-x 1 internally we call it zugferd 2 :-(
}
ze = new ZUGFeRDExporterFromPDFA().load(pdfName);
ze.setProducer("Mustang-cli")
.setZUGFeRDVersion(zfIntVersion)
.setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile);
ze = new ZUGFeRDExporterFromPDFA();
if (ignoreInputErrors) {
((ZUGFeRDExporterFromA1) ze).ignorePDFAErrors();
((ZUGFeRDExporterFromPDFA) ze).ignorePDFAErrors();
}
}
for (FileAttachment attachment : attachments) {
((ZUGFeRDExporterFromA3) ze).attachFile(attachment.getFilename(), attachment.getData(), attachment.getMimetype(), attachment.getRelation());
}
// ze = ze.load(pdfName);
ze.load(pdfName);
ze.setProducer("Mustang-cli")
.setZUGFeRDVersion(zfIntVersion)
.setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile);
if (format.equals("zf")) {
ze.disableFacturX();
@@ -737,7 +741,9 @@ public class Main {
System.out.println("Written to " + outName);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
if (LOGGER != null) {
LOGGER.error(e.getMessage(), e);
}
System.err.println(e.getMessage());
}
}
@@ -837,14 +843,9 @@ public class Main {
} else {
zvi.toPDF(sourceName, outName);
}
} 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) {
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
System.err.println(e.getMessage());
}
System.out.println("Written to " + outName);
@@ -871,11 +872,8 @@ public class Main {
* @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
try (InputStream 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.");
}
@@ -883,15 +881,11 @@ public class Main {
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);
try (FileOutputStream 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;
@@ -913,7 +907,8 @@ public class Main {
if (fileName == null)
return false;
File f = new File(fileName);
return f.exists();
// "exists" also returns true for directories
return f.isFile();
}
}

View File

@@ -14,9 +14,6 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmlunit.builder.Input;
import org.xmlunit.xpath.JAXPXPathEngine;
import org.xmlunit.xpath.XPathEngine;
import org.mustangproject.validator.ZUGFeRDValidator;
import static org.xmlunit.assertj.XmlAssert.assertThat;
@@ -50,25 +47,23 @@ public class ValidatorFileWalker
Date date = new Date();
String expectedString="valid";
if (!expectValid) {
expectedString="invalid";
}
expectedString="invalid";
}
if ((attr!=null)&&(attr.isRegularFile())) {
if (matcher.matches(file.getFileName())) {
boolean thisResultValid=true;
String thisResultString=" valid";
try {
assertThat(zul.validate(file.toAbsolutePath().toString())).valueByXPath("/validation/summary/@status")
.asString()
.isEqualTo(expectedString);
} catch (AssertionError ae) {
thisResultValid=false;
thisResultString="invalid";
allValid=false;
}
LOGGER.info(String.format("\n@%s Testing file %d: %s (%s)", dateFormat.format(date), fileCount++, thisResultString, file));
}
try {
assertThat(zul.validate(file.toAbsolutePath().toString())).valueByXPath("/validation/summary/@status")
.asString()
.isEqualTo(expectedString);
} catch (AssertionError ae) {
thisResultString="invalid";
allValid=false;
}
LOGGER.info(String.format("\n@%s Testing file %d: %s (%s)", dateFormat.format(date), fileCount++, thisResultString, file));
}
}
return FileVisitResult.CONTINUE;
}

View File

@@ -4,33 +4,53 @@ Mustangproject
Source code repository for the [Mustang project](http://www.mustangproject.org/) open source java PDF invoice metadata library in ZUGFeRD format.
License
Build
-----
Subject to the Apache license http://www.apache.org/licenses/LICENSE-2.0.html
These are the recommended dependencies for the project:
Running
-----
- OpenJDK 21.0.2 2024-01-16
- Apache Maven 3.9.6
This project requires Maven to run. Build project with "mvn clean install". This will build the project, test it and install the artifacts to local cache. After that the mustang jar can be used.
You can build the project with:
More information in [the mustang documentation](https://github.com/ZUGFeRD/mustangproject/blob/master/doc/ZugferdDev.en.pdf?raw=true).
```shell
mvn clean install
```
This will run the tests, build the project artefacts, and install the artifacts to the local
cache. After that the mustang JAR can be used.
More information on how to develop **on** mustang:
- [Developer documentation](https://github.com/ZUGFeRD/mustangproject/blob/master/doc/development_documentation.md)
Usage
-----
If you setup a Maven project, you can grab the artifacts using
If you set up a Maven project, you can reference the mustang artifact like this:
```xml
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.10.0</version>
<version>2.12.0</version>
</dependency>
```
Further docs on how to develop **with** mustang:
- [ZugferdDev.en.pdf](https://github.com/ZUGFeRD/mustangproject/blob/master/doc/ZugferdDev.en.pdf?raw=true): The English mustang user documentation.
- [ZugferdDev.de.pdf](https://github.com/ZUGFeRD/mustangproject/blob/master/doc/ZugferdDev.de.pdf?raw=true): The German mustang user documentation.
- [Usage examples](https://www.mustangproject.org/use/): Read and write electronic invoices.
- [Mustang classes](https://www.mustangproject.org/invoice-class/): Using the mustang classes.
Contact
-----
Developer: Jochen Stärk. For questions please contact Jochen at jstaerk [at] usegroup.de
License
-----
Subject to the [Apache-2.0 license](http://www.apache.org/licenses/LICENSE-2.0.html).

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,373 +0,0 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

View File

@@ -1,26 +0,0 @@
= Demo Documentation Component B
// URLs
:url-project: https://antora.org
:url-docs: https://docs.antora.org
:url-org: https://gitlab.com/antora
:url-group: {url-org}/demo
:url-demo-site: https://antora.gitlab.io/demo/docs-site
:url-site-readme: {url-group}/docs-site/blob/master/README.adoc
:url-opendevise: https://opendevise.com
Component B is an example of a documentation component.
It is used by the {url-demo-site}[Antora Demo site].
The playbook and instructions for the Demo site are located in the {url-site-readme}[Demo site playbook project].
== Resources
* {url-project}[Antora Project Site]
* {url-docs}[Antora Docs]
* {url-org}[Antora Repositories]
== Copyright and License
Copyright (C) 2017-present by OpenDevise Inc. and the individual contributors to Antora.
Use of this software is granted under the terms of the https://www.mozilla.org/en-US/MPL/2.0/[Mozilla Public License Version 2.0] (MPL-2.0).
See link:LICENSE[] to find the full license text.

View File

@@ -1,21 +0,0 @@
# This file represents "software".
# This file helps show that documentation files can be in the same repository as software.
rescue => ex
begin
context = %(asciidoctor: FAILED: #{attrs['docfile'] || '<stdin>'}: Failed to load AsciiDoc document)
if ex.respond_to? :exception
# The original message must be explicitely preserved when wrapping a Ruby exception
wrapped_ex = ex.exception %(#{context} - #{ex.message})
# JRuby automatically sets backtrace, but not MRI
wrapped_ex.set_backtrace ex.backtrace
else
# Likely a Java exception class
wrapped_ex = ex.class.new context, ex
wrapped_ex.stack_trace = ex.stack_trace
end
rescue
wrapped_ex = ex
end
raise wrapped_ex
end

View File

@@ -1,7 +0,0 @@
name: mustang
title: Mustang Library
version: 2.6.1
prerelease: -beta.1
nav:
- modules/ROOT/nav.adoc
- modules/module-one/nav.adoc

View File

@@ -1 +0,0 @@
* xref:index.adoc[]

View File

@@ -1,33 +0,0 @@
= Welcome to Component B!
:navtitle: Welcome
This is the automatic start page for version *{page-component-display-version}* of Component B.
Component B is one of two documentation components in the Antora Demo.
The other docs component, Component A, can be accessed using the component selector menu (aka component drawer) at the bottom of the menu on the left side of the page.
== Page source
This page is sourced from the AsciiDoc file named [.path]_index.adoc_ that is located at [.path]_demo-component-b/docs/modules/ROOT/pages_.
=== Why is this the home page of Component B?
This page is automatically used as the start page of Component B because it is stored in the ROOT module and named [.path]_index.adoc_.
=== Why is this the home page of the Antora Demo site?
This page is used as the home page for the Antora Demo because it is assigned as the site `start_page` in the Demo site's playbook file [.path]_site.yml_.
== Cross reference syntax to target this page
To create a cross reference *to this page from another page in the ROOT module of Component B*, the xref syntax would be `\xref:index.adoc[]`.
To create a cross reference *to this page from a page in Module One of Component B*, the xref syntax would be `\xref:ROOT:index.adoc[]`.
=== Always target the latest version of this page
To create a cross reference *to the latest version of this page from a page in Component A*, the xref syntax would be `\xref:component-b::index.adoc[]`.
=== Target a specific version of this page
To create a cross reference *to version 1.0 of this page from a page in Component A*, the xref syntax would be `\xref:1.0@component-b::index.adoc[]`.

View File

@@ -1 +0,0 @@
* xref:overview.adoc[]

View File

@@ -1,21 +0,0 @@
= Module One Overview
This is version *{page-component-display-version}* of Module One in Component B.
== Page source
This page is sourced from [.path]_demo-component-b/docs/modules/module-one/pages/overview.adoc_.
== Cross reference syntax to target this page
To create a cross reference *to this page from another page in Module One*, the xref syntax would be `\xref:overview.adoc[]`.
To create a cross reference *to this page from a page in the ROOT module of Component B*, the xref syntax would be `\xref:module-one:overview.adoc[]`.
=== Always target the latest version of this page
To create a cross reference *to the latest version of this page from a page in Component A*, the xref syntax would be `\xref:component-b:module-one:overview.adoc[]`.
=== Target a specific version of this page
To create a cross reference *to version 1.0 of this page from a page in Component A*, the xref syntax would be `\xref:1.0@component-b:module-one:overview.adoc[]`.

View File

@@ -1,5 +1,5 @@
## General approach
## Typical process
1. build
@@ -29,6 +29,18 @@ 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
## Typical workflow
If e.g. new elements or attributes are added, they are often added
* in the object so that a developer can use them
* in the interface so that a old fashioned developer could use them as well
* in the pullprovider so that it actually finds it's way into the XML
* in at least one test (the ...edgeTest are supposed to handle edge cases, ~all bells and whistles, maybe it fits there), after the test has been run this should at least once be
* validated. If that works one can start implementing the
* reading part (along with tests), then it needs to be
* documented e.g. on the homepage and
* communicated, at the very least by mentioning it in the history.md
## Architecture
Mustang contains a library to read/write e-invoices,
@@ -155,16 +167,16 @@ In .m2 also need a toolchains.xml which defines a Sun JDK 1.8 target like the fo
<?xml version="1.0" encoding="UTF-8"?>
<toolchains>
<!-- JDK toolchains -->
<toolchain>
<type>jdk</type>
<provides>
<version>8</version>
<vendor>adopt</vendor>
</provides>
<configuration>
<jdkHome>C:\Program Files\Eclipse Adoptium\jdk-8.0.352.8-hotspot</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<version>11</version>
<vendor>adopt</vendor>
</provides>
<configuration>
<jdkHome>C:\Program Files\Eclipse Adoptium\jdk-11.0.23.9-hotspot</jdkHome>
</configuration>
</toolchain>
</toolchains>
```

183
doc/mustang-validation.xsd Normal file
View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="validation">
<xs:complexType>
<xs:sequence>
<xs:element ref="pdf"/>
<xs:element ref="messages"/>
<xs:element ref="summary"/>
</xs:sequence>
<xs:attribute name="datetime" use="required"/>
<xs:attribute name="filename" use="required" type="xs:NCName"/>
</xs:complexType>
</xs:element>
<xs:element name="pdf">
<xs:complexType>
<xs:sequence>
<xs:element ref="report"/>
<xs:element ref="info"/>
<xs:element ref="messages"/>
<xs:element ref="summary"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="report">
<xs:complexType>
<xs:sequence>
<xs:element ref="buildInformation"/>
<xs:element ref="jobs"/>
<xs:element ref="batchSummary"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="buildInformation">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="releaseDetails"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="releaseDetails">
<xs:complexType>
<xs:attribute name="buildDate" use="required" type="xs:dateTime"/>
<xs:attribute name="id" use="required" type="xs:NCName"/>
<xs:attribute name="version" use="required" type="xs:NMTOKEN"/>
</xs:complexType>
</xs:element>
<xs:element name="jobs">
<xs:complexType>
<xs:sequence>
<xs:element ref="job"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="job">
<xs:complexType>
<xs:sequence>
<xs:element ref="item"/>
<xs:element ref="validationReport"/>
<xs:element ref="duration"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item">
<xs:complexType>
<xs:sequence>
<xs:element ref="name"/>
</xs:sequence>
<xs:attribute name="size" use="required" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="name" type="xs:string"/>
<xs:element name="validationReport">
<xs:complexType>
<xs:sequence>
<xs:element ref="details"/>
</xs:sequence>
<xs:attribute name="isCompliant" use="required" type="xs:boolean"/>
<xs:attribute name="profileName" use="required"/>
<xs:attribute name="statement" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="details">
<xs:complexType>
<xs:attribute name="failedChecks" use="required" type="xs:integer"/>
<xs:attribute name="failedRules" use="required" type="xs:integer"/>
<xs:attribute name="passedChecks" use="required" type="xs:integer"/>
<xs:attribute name="passedRules" use="required" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="batchSummary">
<xs:complexType>
<xs:sequence>
<xs:element ref="validationReports"/>
<xs:element ref="featureReports"/>
<xs:element ref="repairReports"/>
<xs:element ref="duration"/>
</xs:sequence>
<xs:attribute name="encrypted" use="required" type="xs:integer"/>
<xs:attribute name="failedToParse" use="required" type="xs:integer"/>
<xs:attribute name="outOfMemory" use="required" type="xs:integer"/>
<xs:attribute name="totalJobs" use="required" type="xs:integer"/>
<xs:attribute name="veraExceptions" use="required" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="validationReports">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:integer">
<xs:attribute name="compliant" use="required" type="xs:integer"/>
<xs:attribute name="failedJobs" use="required" type="xs:integer"/>
<xs:attribute name="nonCompliant" use="required" type="xs:integer"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="featureReports">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:integer">
<xs:attribute name="failedJobs" use="required" type="xs:integer"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="repairReports">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:integer">
<xs:attribute name="failedJobs" use="required" type="xs:integer"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="info">
<xs:complexType>
<xs:sequence>
<xs:element ref="signature"/>
<xs:element ref="duration"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="signature" type="xs:NCName"/>
<xs:element name="duration">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:NMTOKEN">
<xs:attribute name="finish" type="xs:integer"/>
<xs:attribute name="start" type="xs:integer"/>
<xs:attribute name="unit" type="xs:NCName"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="messages">
<xs:complexType>
<xs:choice>
<xs:element ref="exception"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="error"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="notice"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="exception">
<xs:complexType mixed="true">
<xs:attribute name="type" use="required" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="error">
<xs:complexType mixed="true">
<xs:attribute name="type" use="required" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="notice">
<xs:complexType mixed="true">
<xs:attribute name="type" use="required" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="summary">
<xs:complexType>
<xs:attribute name="status" use="required" type="xs:NCName"/>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -1,345 +1,364 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<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">
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.12.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.9.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.9.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII)</name>
<description>FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT Cross Industry Invoice based formats Factur-X/ZUGFeRD, XRechnung and Order-X in your invoice PDFs.
<artifactId>library</artifactId>
<version>2.12.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII)</name>
<description>FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT
Cross Industry Invoice based formats Factur-X/ZUGFeRD, XRechnung and Order-X in your invoice PDFs.
</description>
<url>http://www.mustangproject.org/</url>
<scm>
<connection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</connection>
<developerConnection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</developerConnection>
<url>https://github.com/ZUGFeRD/mustangproject</url>
<tag>core-2.3.2</tag>
</scm>
<repositories>
<repository><!-- for jargs -->
<id>sonatype-oss-public</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>internal.repo</id>
<name>Temporary Staging Repository</name>
<url>file://${project.build.directory}/mvn-repo</url>
</repository>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<github.global.server>github</github.global.server>
<additionalparam>-Xdoclint:none</additionalparam>
<!-- Skip error check for javadoc -->
<maven.compiler.compilerVersion>8</maven.compiler.compilerVersion>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<maven.deploy.skip>true</maven.deploy.skip><!-- do deploy to maven central, parent project does not and inherits -->
<url>http://www.mustangproject.org/</url>
<scm>
<connection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</connection>
<developerConnection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</developerConnection>
<url>https://github.com/ZUGFeRD/mustangproject</url>
<tag>core-2.3.2</tag>
</scm>
<repositories>
<repository><!-- for jargs -->
<id>sonatype-oss-public</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>internal.repo</id>
<name>Temporary Staging Repository</name>
<url>file://${project.build.directory}/mvn-repo</url>
</repository>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<github.global.server>github</github.global.server>
<additionalparam>-Xdoclint:none</additionalparam>
<!-- Skip error check for javadoc -->
<maven.compiler.compilerVersion>11</maven.compiler.compilerVersion>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<maven.deploy.skip>true
</maven.deploy.skip><!-- do deploy to maven central, parent project does not and inherits -->
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE -->
<dependency>
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
<version>9.9.0-1</version>
</dependency><!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/fop -->
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>fop</artifactId>
<version>2.9</version>
</dependency>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE -->
<dependency>
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
<version>12.4</version>
</dependency><!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/fop -->
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>fop</artifactId>
<version>2.9</version>
<exclusions>
<exclusion>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>org.eclipse.angus</groupId>
<artifactId>angus-activation</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>preflight</artifactId>
<version>2.0.27</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.27</version>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
<!-- CII to UBL conversion -->
<dependency>
<groupId>com.helger</groupId>
<artifactId>en16931-cii2ubl</artifactId>
<version>1.4.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<version>2.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-assertj</artifactId>
<version>2.9.1</version>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>preflight</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<!-- API -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
<!-- CII to UBL conversion -->
<dependency>
<groupId>com.helger</groupId>
<artifactId>en16931-cii2ubl</artifactId>
<version>2.2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<version>2.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-assertj</artifactId>
<version>2.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
mvn clean compile assembly:single -->
<!-- or whatever version you use -->
<source>8</source>
<target>8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<excludes>
<exclude>**/logback.xml</exclude>
</excludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestSections>
<manifestSection>
<name>FreeSans.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>FreeSerif.ttf</name>
<manifestEntries>
<Content-Type>application/x-font</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>Times-Bold.ttf</name>
<manifestEntries>
<Content-Type>application/x-font</Content-Type>
</manifestEntries>
</manifestSection>
</manifestSections>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<minimizeJar>false</minimizeJar><!-- no longer java 11 compatible if set to true because it removes e.g. javax/xml/bind/annotation/XmlSchema-->
<filters>
<!-- or whatever version you use -->
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<excludes>
<exclude>**/logback.xml</exclude>
</excludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestSections>
<manifestSection>
<name>FreeSans.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>FreeSerif.ttf</name>
<manifestEntries>
<Content-Type>application/x-font</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>Times-Bold.ttf</name>
<manifestEntries>
<Content-Type>application/x-font</Content-Type>
</manifestEntries>
</manifestSection>
</manifestSections>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<minimizeJar>false
</minimizeJar><!-- no longer java 11 compatible if set to true because it removes e.g. javax/xml/bind/annotation/XmlSchema-->
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
<filter>
<artifact>log4j:log4j</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>commons-logging:commons-logging</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<!--exclude>classworlds:classworlds</exclude> <exclude>junit:junit</exclude>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
<filter>
<artifact>log4j:log4j</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>commons-logging:commons-logging</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<!--exclude>classworlds:classworlds</exclude> <exclude>junit:junit</exclude>
<exclude>jmock:*</exclude> <exclude>*:xml-apis</exclude> <exclude>org.apache.maven:lib:tests</exclude>
<exclude>log4j:log4j:jar:</exclude -->
</excludes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<id>filtering-java-templates</id>
<goals>
<goal>filter-sources</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</excludes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<id>filtering-java-templates</id>
<goals>
<goal>filter-sources</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile> <!-- enforce building binaries with Java 1.8 for Maven Central, otherwise using them e.g. as jar will throw a version exception-->
<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-toolchains-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>8</version>
<vendor>adopt</vendor>
</jdk>
</toolchains>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<mailingLists>
<mailingList>
<name>User List</name>
<archive>https://groups.google.com/forum/?hl=de#!forum/mustangproject</archive>
</mailingList>
</mailingLists>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
<comments>A business-friendly OSS license</comments>
</license>
</licenses>
<developers>
<developer>
<name>Jochen Stärk</name>
<email>jstaerk@usegroup.de</email>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
</developer>
<developer>
<name>Alexander Schmidt</name>
<email>schmidt.alexander@mail.de</email>
<roles>
<role>developer</role>
</roles>
</developer>
</developers>
<profiles>
<profile> <!-- enforce building binaries with Java 1.8 for Maven Central, otherwise using them e.g. as jar will throw a version exception-->
<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-toolchains-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>11</version>
<vendor>adopt</vendor>
</jdk>
</toolchains>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<mailingLists>
<mailingList>
<name>User List</name>
<archive>https://groups.google.com/forum/?hl=de#!forum/mustangproject</archive>
</mailingList>
</mailingLists>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
<comments>A business-friendly OSS license</comments>
</license>
</licenses>
<developers>
<developer>
<name>Jochen Stärk</name>
<email>jstaerk@usegroup.de</email>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
</developer>
<developer>
<name>Alexander Schmidt</name>
<email>schmidt.alexander@mail.de</email>
<roles>
<role>developer</role>
</roles>
</developer>
</developers>
</project>

View File

@@ -1,14 +1,11 @@
package org.mustangproject;
import org.mustangproject.ZUGFeRD.IExportableTransaction;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
import java.math.BigDecimal;
/***
* (absolute) allowances on item and document level
*/
public class Allowance extends Charge implements IZUGFeRDAllowanceCharge {
public class Allowance extends Charge {
/***
* bean constructor

View File

@@ -5,9 +5,7 @@ import java.io.Serializable;
import com.helger.commons.error.list.ErrorList;
import com.helger.en16931.cii2ubl.CIIToUBL23Converter;
import com.helger.ubl21.UBL21Writer;
import com.helger.ubl22.UBL22Writer;
import com.helger.ubl23.UBL23Writer;
import com.helger.ubl23.UBL23Marshaller;
/***
* converts a Cross Industry Invoice XML file to a UBL XML file
@@ -23,39 +21,15 @@ public class CIIToUBL {
final ErrorList occurred=new ErrorList();
final CIIToUBL23Converter cc=new CIIToUBL23Converter();
final Serializable aUBL = cc.convertCIItoUBL(input, occurred);
if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.invoice_21.InvoiceType)
if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.invoice_23.InvoiceType)
{
UBL21Writer.invoice ()
.setFormattedOutput (true)
.write ((oasis.names.specification.ubl.schema.xsd.invoice_21.InvoiceType) aUBL, output);
}
else if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.creditnote_21.CreditNoteType)
{
UBL21Writer.creditNote ()
.setFormattedOutput (true)
.write ((oasis.names.specification.ubl.schema.xsd.creditnote_21.CreditNoteType) aUBL, output);
}
else if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.invoice_22.InvoiceType)
{
UBL22Writer.invoice ()
.setFormattedOutput (true)
.write ((oasis.names.specification.ubl.schema.xsd.invoice_22.InvoiceType) aUBL, output);
}
else if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.creditnote_22.CreditNoteType)
{
UBL22Writer.creditNote ()
.setFormattedOutput (true)
.write ((oasis.names.specification.ubl.schema.xsd.creditnote_22.CreditNoteType) aUBL, output);
}
else if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.invoice_23.InvoiceType)
{
UBL23Writer.invoice ()
UBL23Marshaller.invoice ()
.setFormattedOutput (true)
.write ((oasis.names.specification.ubl.schema.xsd.invoice_23.InvoiceType) aUBL, output);
}
else if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.creditnote_23.CreditNoteType)
{
UBL23Writer.creditNote ()
UBL23Marshaller.creditNote ()
.setFormattedOutput (true)
.write ((oasis.names.specification.ubl.schema.xsd.creditnote_23.CreditNoteType) aUBL, output);
}

View File

@@ -0,0 +1,59 @@
package org.mustangproject;
import org.mustangproject.ZUGFeRD.IZUGFeRDCashDiscount;
import java.math.BigDecimal;
/***
* A class to represent discounts for early payments ("Skonto")
*/
public class CashDiscount implements IZUGFeRDCashDiscount {
/***
* the reduction percent allowed in the period
*/
protected BigDecimal percent;
/***
* the period (usually days) count how long the percent apply
*/
protected Integer days=null;
/***
* Create a cash discount (skonto) with the specified height in the specified period.
* Should someone add more period types than just "days" there
* is be space for a (optional) third parameter
*
* @param percent max 3 decimals "behind the dot", more precision is currently ignored
* @param days the count of the periods (usually days) the percentage applies
*/
public CashDiscount(BigDecimal percent, int days) {
this.percent = percent;
this.days = days;
}
/***
* @return this particular cash discount as cross industry invoice XML
*/
public String getAsCII() {
return "<ram:SpecifiedTradePaymentTerms>"+
"<ram:Description>Cash Discount</ram:Description>"+
" <ram:ApplicableTradePaymentDiscountTerms>"+
" <ram:BasisPeriodMeasure unitCode=\"DAY\">"+days+"</ram:BasisPeriodMeasure>"+
" <ram:CalculationPercent>"+XMLTools.nDigitFormat(percent,3)+"</ram:CalculationPercent>"+
" </ram:ApplicableTradePaymentDiscountTerms>"+
"</ram:SpecifiedTradePaymentTerms>";
}
/***
* since EN16931 voted not to have (or even allow) cash discounts in their core invoice the german
* XRechnung CIUS defined it's own proprietary format for a freetext field
* @return this particular cash discount in proprietary xrechnung format
*/
public String getAsXRechnung() {
return "#SKONTO#TAGE="+days+"#PROZENT="+XMLTools.nDigitFormat(percent,2)+"#\n";
}
}

View File

@@ -1,9 +1,7 @@
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;

View File

@@ -111,10 +111,10 @@ public class Contact implements IZUGFeRDExportableContact {
Node currentItemNode = nodes.item(nodeIndex);
if (currentItemNode.getLocalName() != null) {
if (currentItemNode.getLocalName().equals("PersonName")) {
if (currentItemNode.getLocalName().equals("PersonName")/*CII*/||currentItemNode.getLocalName().equals("Name")/*UBL*/) {
setName(currentItemNode.getFirstChild().getNodeValue());
}
if (currentItemNode.getLocalName().equals("TelephoneUniversalCommunication")) {
if (currentItemNode.getLocalName().equals("TelephoneUniversalCommunication")) { /*CII*/
NodeList tel = currentItemNode.getChildNodes();
for (int telChildIndex = 0; telChildIndex < tel.getLength(); telChildIndex++) {
if (tel.item(telChildIndex).getLocalName() != null) {
@@ -123,8 +123,10 @@ public class Contact implements IZUGFeRDExportableContact {
}
}
}
} else if (currentItemNode.getLocalName().equals("Telephone")) { /* UBL */
setPhone(currentItemNode.getTextContent());
}
if (currentItemNode.getLocalName().equals("EmailURIUniversalCommunication")) {
if (currentItemNode.getLocalName().equals("EmailURIUniversalCommunication")) { /* CII */
NodeList email = currentItemNode.getChildNodes();
for (int emailChildIndex = 0; emailChildIndex < email.getLength(); emailChildIndex++) {
if (email.item(emailChildIndex).getLocalName() != null) {
@@ -133,6 +135,8 @@ public class Contact implements IZUGFeRDExportableContact {
}
}
}
} else if (currentItemNode.getLocalName().equals("ElectronicMail")) { /* UBL */
setEMail(currentItemNode.getTextContent());
}
}
}

View File

@@ -26,12 +26,7 @@ import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.mustangproject.ZUGFeRD.IExportableTransaction;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTradeParty;
import org.mustangproject.ZUGFeRD.IZUGFeRDPaymentTerms;
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlement;
import org.mustangproject.ZUGFeRD.*;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -47,20 +42,21 @@ 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, invoiceReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null;
protected Date issueDate = null, dueDate = null, deliveryDate = null;
protected TradeParty sender = null, recipient = null, deliveryAddress = null;
@JsonDeserialize(contentAs=Item.class)
protected ArrayList<CashDiscount> cashDiscounts = null;
@JsonDeserialize(contentAs = Item.class)
protected ArrayList<IZUGFeRDExportableItem> ZFItems = null;
protected ArrayList<String> notes = null;
private List<IncludedNote> includedNotes = null;
protected String sellerOrderReferencedDocumentID;
private List<IncludedNote> includedNotes = null;
protected String sellerOrderReferencedDocumentID;
protected String contractReferencedDocument = null;
protected ArrayList<FileAttachment> xmlEmbeddedFiles=null;
protected ArrayList<FileAttachment> xmlEmbeddedFiles = null;
protected BigDecimal totalPrepaidAmount = null;
protected Date detailedDeliveryDateStart = null;
protected Date detailedDeliveryPeriodEnd = null;
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>(),
Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>();
Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>();
protected IZUGFeRDPaymentTerms paymentTerms = null;
protected Date invoiceReferencedIssueDate;
protected String specifiedProcuringProjectID = null;
@@ -70,6 +66,7 @@ public class Invoice implements IExportableTransaction {
public Invoice() {
ZFItems = new ArrayList<>();
cashDiscounts = new ArrayList<>();
setCurrency("EUR");
}
@@ -79,7 +76,7 @@ public class Invoice implements IExportableTransaction {
}
@Override
public String getContractReferencedDocument() {
public String getContractReferencedDocument() {
return contractReferencedDocument;
}
@@ -100,14 +97,14 @@ public class Invoice implements IExportableTransaction {
public Invoice embedFileInXML(FileAttachment fa) {
if (xmlEmbeddedFiles == null) {
xmlEmbeddedFiles= new ArrayList<>();
xmlEmbeddedFiles = new ArrayList<>();
}
xmlEmbeddedFiles.add(fa);
return this;
}
@Override
public FileAttachment[] getAdditionalReferencedDocuments() {
public FileAttachment[] getAdditionalReferencedDocuments() {
if (xmlEmbeddedFiles == null) {
return null;
}
@@ -115,6 +112,10 @@ public class Invoice implements IExportableTransaction {
}
@Override
public IZUGFeRDCashDiscount[] getCashDiscounts() {
return cashDiscounts.toArray(new IZUGFeRDCashDiscount[0]);
}
@Override
public String getNumber() {
@@ -139,6 +140,7 @@ public class Invoice implements IExportableTransaction {
documentCode = DocumentCodeTypeConstants.CORRECTEDINVOICE;
return this;
}
public Invoice setCreditNote() {
documentCode = DocumentCodeTypeConstants.CREDITNOTE;
return this;
@@ -229,16 +231,18 @@ public class Invoice implements IExportableTransaction {
public String getBuyerOrderReferencedDocumentID() {
return buyerOrderReferencedDocumentID;
}
@Override
public String getSellerOrderReferencedDocumentID() {
return sellerOrderReferencedDocumentID;
}
public Invoice setSellerOrderReferencedDocumentID(String sellerOrderReferencedDocumentID) {
this.sellerOrderReferencedDocumentID = sellerOrderReferencedDocumentID;
return this;
}
public Invoice setSellerOrderReferencedDocumentID(String sellerOrderReferencedDocumentID) {
this.sellerOrderReferencedDocumentID = sellerOrderReferencedDocumentID;
return this;
}
/***
* usually the order number
* @param buyerOrderReferencedDocumentID string with number
@@ -258,22 +262,23 @@ public class Invoice implements IExportableTransaction {
this.invoiceReferencedDocumentID = invoiceReferencedDocumentID;
return this;
}
@Override
public String getInvoiceReferencedDocumentID() {
return invoiceReferencedDocumentID;
}
@Override
public Date getInvoiceReferencedIssueDate() {
return invoiceReferencedIssueDate;
}
@Override
public Date getInvoiceReferencedIssueDate() {
return invoiceReferencedIssueDate;
}
public Invoice setInvoiceReferencedIssueDate(Date issueDate) {
this.invoiceReferencedIssueDate = issueDate;
return this;
}
@Override
public Invoice setInvoiceReferencedIssueDate(Date issueDate) {
this.invoiceReferencedIssueDate = issueDate;
return this;
}
@Override
public String getBuyerOrderReferencedDocumentIssueDateTime() {
return buyerOrderReferencedDocumentIssueDateTime;
}
@@ -285,7 +290,7 @@ public class Invoice implements IExportableTransaction {
* @return fluent setter
*/
public Invoice setTotalPrepaidAmount(BigDecimal prepaid) {
totalPrepaidAmount=prepaid;
totalPrepaidAmount = prepaid;
return this;
}
@@ -380,13 +385,13 @@ public class Invoice implements IExportableTransaction {
@Override
public String getOwnLocation() {
public String getOwnLocation() {
return sender.getLocation();
}
@Override
public String getOwnCountry() {
public String getOwnCountry() {
return sender.getCountry();
}
@@ -399,12 +404,12 @@ public class Invoice implements IExportableTransaction {
return notes.toArray(new String[0]);
}
@Override
public List<IncludedNote> getNotesWithSubjectCode() {
return includedNotes;
}
@Override
public List<IncludedNote> getNotesWithSubjectCode() {
return includedNotes;
}
@Override
@Override
public String getCurrency() {
return currency;
}
@@ -455,7 +460,7 @@ public class Invoice implements IExportableTransaction {
}
@Override
public IZUGFeRDExportableTradeParty getSender() {
public TradeParty getSender() {
return sender;
}
@@ -473,13 +478,14 @@ public class Invoice implements IExportableTransaction {
}
@Override
public IZUGFeRDExportableTradeParty getRecipient() {
public TradeParty getRecipient() {
return recipient;
}
/**
* required.
* sets the invoice receiving institution = invoicee
*
* @param recipient the invoicee organisation
* @return fluent setter
*/
@@ -491,6 +497,7 @@ public class Invoice implements IExportableTransaction {
/**
* required.
* sets the invoicing institution = invoicer
*
* @param sender the invoicer
* @return fluent setter
*/
@@ -508,8 +515,8 @@ public class Invoice implements IExportableTransaction {
if (Allowances.isEmpty()) {
return null;
} else {
return Allowances.toArray(new IZUGFeRDAllowanceCharge[0]);
}
return Allowances.toArray(new IZUGFeRDAllowanceCharge[0]);
}
}
@@ -518,8 +525,8 @@ public class Invoice implements IExportableTransaction {
if (Charges.isEmpty()) {
return null;
} else {
return Charges.toArray(new IZUGFeRDAllowanceCharge[0]);
}
return Charges.toArray(new IZUGFeRDAllowanceCharge[0]);
}
}
@@ -528,8 +535,8 @@ public class Invoice implements IExportableTransaction {
if (LogisticsServiceCharges.isEmpty()) {
return null;
} else {
return LogisticsServiceCharges.toArray(new IZUGFeRDAllowanceCharge[0]);
}
return LogisticsServiceCharges.toArray(new IZUGFeRDAllowanceCharge[0]);
}
}
@@ -540,7 +547,7 @@ public class Invoice implements IExportableTransaction {
return null;
}
return ((TradeParty) getSender()).getAsTradeSettlement();
return getSender().getAsTradeSettlement();
}
@@ -569,22 +576,33 @@ public class Invoice implements IExportableTransaction {
this.deliveryAddress = deliveryAddress;
return this;
}
/***
* Adds a cash discount (skonto)
* @param c the CashDiscount percent/period combination
* @return fluent setter
*/
public Invoice addCashDiscount(CashDiscount c) {
this.cashDiscounts.add(c);
return this;
}
@Override
public IZUGFeRDExportableItem[] getZFItems() {
return ZFItems.toArray(new IZUGFeRDExportableItem[0]);
}
public void setZFItems(ArrayList<IZUGFeRDExportableItem> ims) {
ZFItems=ims;
public void setZFItems(ArrayList<IZUGFeRDExportableItem> ims) {
ZFItems = ims;
}
/**
* required
* adds invoice "lines" :-)
* @see Item
*
* @param item the invoice line
* @return fluent setter
* @see Item
*/
public Invoice addItem(IZUGFeRDExportableItem item) {
ZFItems.add(item);
@@ -669,6 +687,7 @@ public class Invoice implements IExportableTransaction {
/**
* adds a free text paragraph, which will become an includedNote element
*
* @param text freeform UTF8 plain text
* @return fluent setter
*/
@@ -679,129 +698,138 @@ public class Invoice implements IExportableTransaction {
notes.add(text);
return this;
}
public Invoice addNotes(Collection<IncludedNote> notes) {
if (notes == null) {
return this;
}
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.addAll(notes);
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#AAI}
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addGeneralNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.generalNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#REG}
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addRegulatoryNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.regulatoryNote(content));
return this;
}
public Invoice addNotes(Collection<IncludedNote> notes) {
if (notes == null) {
return this;
}
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.addAll(notes);
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#ABL}
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addLegalNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.legalNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#AAI}
*
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addGeneralNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.generalNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#CUS}
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addCustomsNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.customsNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#REG}
*
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addRegulatoryNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.regulatoryNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#SUR}
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addSellerNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.sellerNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#ABL}
*
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addLegalNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.legalNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#CUS}
*
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addCustomsNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.customsNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#SUR}
*
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addSellerNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.sellerNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#TXD}
*
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addTaxNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.taxNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#ACY}
*
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addIntroductionNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.introductionNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#AAK}
*
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addDiscountBonusNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.discountBonusNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#TXD}
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addTaxNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.taxNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#ACY}
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addIntroductionNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.introductionNote(content));
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element with explicit
* subjectCode {@link SubjectCode#AAK}
* @param content freeform UTF8 plain text
* @return fluent setter
*/
public Invoice addDiscountBonusNote(String content) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(IncludedNote.discountBonusNote(content));
return this;
}
@Override
public String getSpecifiedProcuringProjectID() {
return specifiedProcuringProjectID;
@@ -841,6 +869,7 @@ public class Invoice implements IExportableTransaction {
/**
* Decide when the VAT should be collected.
*
* @param vatDueDateTypeCode use EventTimeCodeTypeConstants
* @return fluent setter
*/

View File

@@ -1,7 +1,6 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.apache.fop.util.XMLUtil;
import org.mustangproject.ZUGFeRD.IReferencedDocument;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
@@ -12,7 +11,6 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/***
* describes any invoice line
@@ -28,8 +26,8 @@ public class Item implements IZUGFeRDExportableItem {
protected Product product;
protected ArrayList<String> notes = null;
protected ArrayList<ReferencedDocument> referencedDocuments = null;
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<IZUGFeRDAllowanceCharge>(),
Charges = new ArrayList<IZUGFeRDAllowanceCharge>();
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>(),
Charges = new ArrayList<>();
/***
* default constructor
@@ -62,6 +60,7 @@ public class Item implements IZUGFeRDExportableItem {
String vatPercent = null;
String lineTotal = "0";
String unitCode = "0";
String referencedLineID = null;
ArrayList<ReferencedDocument> rdocs = null;
@@ -138,12 +137,22 @@ public class Item implements IZUGFeRDExportableItem {
ReferencedDocument rd = new ReferencedDocument(IssuerAssignedID, TypeCode,
ReferenceTypeCode);
if (rdocs == null) {
rdocs = new ArrayList<ReferencedDocument>();
rdocs = new ArrayList<>();
}
rdocs.add(rd);
}
if ((tradeLineChilds.item(tradeLineChildIndex).getLocalName() != null) && tradeLineChilds.item(tradeLineChildIndex).getLocalName().equals("BuyerOrderReferencedDocument")) {
NodeList docChilds = tradeLineChilds.item(tradeLineChildIndex).getChildNodes();
for (int docIndex = 0; docIndex < docChilds.getLength(); docIndex++) {
String localName = docChilds.item(docIndex).getLocalName();
if ((localName != null) && (localName.equals("LineID"))) {
referencedLineID = docChilds.item(docIndex).getTextContent();
}
}
}
if ((tradeLineChilds.item(tradeLineChildIndex).getLocalName() != null) && tradeLineChilds
.item(tradeLineChildIndex).getLocalName().equals("NetPriceProductTradePrice")) {
NodeList netChilds = tradeLineChilds.item(tradeLineChildIndex).getChildNodes();
@@ -265,6 +274,7 @@ public class Item implements IZUGFeRDExportableItem {
addReferencedDocument(rdoc);
}
}
addReferencedLineID( referencedLineID );
}
@@ -428,7 +438,7 @@ public class Item implements IZUGFeRDExportableItem {
*/
public Item addNote(String text) {
if (notes == null) {
notes = new ArrayList<String>();
notes = new ArrayList<>();
}
notes.add(text);
return this;
@@ -441,7 +451,7 @@ public class Item implements IZUGFeRDExportableItem {
*/
public Item addReferencedDocument(ReferencedDocument doc) {
if (referencedDocuments == null) {
referencedDocuments = new ArrayList<ReferencedDocument>();
referencedDocuments = new ArrayList<>();
}
referencedDocuments.add(doc);
return this;

View File

@@ -2,13 +2,6 @@ package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.mustangproject.ZUGFeRD.*;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/***
* A organisation, i.e. usually a company

View File

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct;
import java.math.BigDecimal;
import java.util.HashMap;
/***
* describes a product, good or service used in an invoice item line
@@ -15,6 +16,8 @@ public class Product implements IZUGFeRDExportableProduct {
protected boolean isReverseCharge = false;
protected boolean isIntraCommunitySupply = false;
protected SchemedID globalId = null;
protected String countryOfOrigin = null;
protected HashMap<String, String> attributes = null;
/***
* default constructor
@@ -63,6 +66,7 @@ public class Product implements IZUGFeRDExportableProduct {
}
@Override
public String getSellerAssignedID() {
return sellerAssignedID;
}
@@ -77,6 +81,7 @@ public class Product implements IZUGFeRDExportableProduct {
return this;
}
@Override
public String getBuyerAssignedID() {
return buyerAssignedID;
}
@@ -183,4 +188,32 @@ public class Product implements IZUGFeRDExportableProduct {
this.VATPercent = VATPercent;
return this;
}
@Override
public String getCountryOfOrigin() {
return this.countryOfOrigin;
}
public Product setCountryOfOrigin(String countryOfOrigin) {
this.countryOfOrigin = countryOfOrigin;
return this;
}
@Override
public HashMap<String, String> getAttributes() {
return this.attributes;
}
public Product setAttributes(HashMap<String, String> attributes) {
this.attributes = attributes;
return this;
}
public Product addAttribute(String name, String value ) {
if ( this.attributes == null ) {
this.attributes = new HashMap<>();
}
this.attributes.put(name, value);
return this;
}
}

View File

@@ -65,154 +65,159 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
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).getLocalName() != null) {
if (itemChilds.item(itemChildIndex).getLocalName().equals("Party")) {
if (currentItemNode.getLocalName() != null) {
String debcurrentChild = currentItemNode.getLocalName();
if (debcurrentChild.equals("Party")) {
NodeList party = itemChilds.item(itemChildIndex).getChildNodes();
for (int partyIndex = 0; partyIndex < party.getLength(); partyIndex++) {
if (party.item(partyIndex).getLocalName() != null) {
NodeList party = currentItemNode.getChildNodes();
for (int partyIndex = 0; partyIndex < party.getLength(); partyIndex++) {
if (party.item(partyIndex).getLocalName() != null) {
String debCN = party.item(partyIndex).getLocalName();
if (debCN.equals("PartyName")) {
if (party.item(partyIndex).getLocalName().equals("PartyName")) {
NodeList partyName = party.item(partyIndex).getChildNodes();
for (int partyNameIndex = 0; partyNameIndex < partyName.getLength(); partyNameIndex++) {
if (partyName.item(partyNameIndex).getLocalName() != null) {
if (partyName.item(partyNameIndex).getLocalName().equals("Name")) {
setName(partyName.item(partyNameIndex).getTextContent());
}
NodeList partyName = party.item(partyIndex).getChildNodes();
for (int partyNameIndex = 0; partyNameIndex < partyName.getLength(); partyNameIndex++) {
if (partyName.item(partyNameIndex).getLocalName() != null) {
if (partyName.item(partyNameIndex).getLocalName().equals("Name")) {
setName(partyName.item(partyNameIndex).getTextContent());
}
}
}
if (party.item(partyIndex).getLocalName().equals("PostalAddress")) {
}
if (debCN.equals("PostalAddress")) {
NodeList postal = party.item(partyIndex).getChildNodes();
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
if (postal.item(postalChildIndex).getLocalName() != null) {
NodeList postal = party.item(partyIndex).getChildNodes();
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
if (postal.item(postalChildIndex).getLocalName() != null) {
if (postal.item(postalChildIndex).getLocalName().equals("StreetName")) {
setStreet(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("AdditionalStreetName")) {
setAdditionalAddress(postal.item(postalChildIndex).getTextContent());
}
//unknow correspondence if (postal.item(postalChildIndex).getLocalName().equals("LineThree")) {
if (postal.item(postalChildIndex).getLocalName().equals("StreetName")) {
setStreet(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("AdditionalStreetName")) {
setAdditionalAddress(postal.item(postalChildIndex).getTextContent());
}
//unknow correspondence if (postal.item(postalChildIndex).getLocalName().equals("LineThree")) {
if (postal.item(postalChildIndex).getLocalName().equals("CityName")) {
setLocation(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("PostalZone")) {
setZIP(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("Country")) {
NodeList country = postal.item(postalChildIndex).getChildNodes();
for (int countryIndex = 0; countryIndex < country.getLength(); countryIndex++) {
if (country.item(countryIndex).getLocalName() != null) {
if (country.item(countryIndex).getLocalName().equals("IdentificationCode")) {
setCountry(country.item(countryIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("CityName")) {
setLocation(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("PostalZone")) {
setZIP(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("Country")) {
NodeList country = postal.item(postalChildIndex).getChildNodes();
for (int countryIndex = 0; countryIndex < country.getLength(); countryIndex++) {
if (country.item(countryIndex).getLocalName() != null) {
if (country.item(countryIndex).getLocalName().equals("IdentificationCode")) {
setCountry(country.item(countryIndex).getTextContent());
}
}
}
if (postal.item(postalChildIndex).getLocalName().equals("AddressLine")) {
NodeList AddressLine = postal.item(postalChildIndex).getChildNodes();
for (int lineIndex = 0; lineIndex < AddressLine.getLength(); lineIndex++) {
if (AddressLine.item(lineIndex).getLocalName() != null) {
if (AddressLine.item(lineIndex).getLocalName().equals("Line")) {
setAdditionalAddressExtension(AddressLine.item(lineIndex).getTextContent());
}
}
if (postal.item(postalChildIndex).getLocalName().equals("AddressLine")) {
NodeList AddressLine = postal.item(postalChildIndex).getChildNodes();
for (int lineIndex = 0; lineIndex < AddressLine.getLength(); lineIndex++) {
if (AddressLine.item(lineIndex).getLocalName() != null) {
if (AddressLine.item(lineIndex).getLocalName().equals("Line")) {
setAdditionalAddressExtension(AddressLine.item(lineIndex).getTextContent());
}
}
}
if (postal.item(postalChildIndex).getLocalName().equals("Name")) {
setName(postal.item(postalChildIndex).getTextContent());
}
}
if (postal.item(postalChildIndex).getLocalName().equals("Name")) {
setName(postal.item(postalChildIndex).getTextContent());
}
}
}
}
}
}
if (itemChilds.item(itemChildIndex).getLocalName().equals("GlobalID")) {
if (itemChilds.item(itemChildIndex).getAttributes().getNamedItem("schemeID") != null) {
SchemedID gid = new SchemedID().setScheme(itemChilds.item(itemChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue()).setId(itemChilds.item(itemChildIndex).getTextContent());
addGlobalID(gid);
}
}
if (itemChilds.item(itemChildIndex).getLocalName().equals("DefinedTradeContact")) {
NodeList contact = itemChilds.item(itemChildIndex).getChildNodes();
setContact(new Contact(contact));
}
if (itemChilds.item(itemChildIndex).getLocalName().equals("PostalTradeAddress")) {
NodeList postal = itemChilds.item(itemChildIndex).getChildNodes();
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
if (postal.item(postalChildIndex).getLocalName() != null) {
if (postal.item(postalChildIndex).getLocalName().equals("LineOne")) {
setStreet(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("LineTwo")) {
setAdditionalAddress(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("LineThree")) {
setAdditionalAddressExtension(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("CityName")) {
setLocation(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("PostcodeCode")) {
setZIP(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("CountryID")) {
setCountry(postal.item(postalChildIndex).getTextContent());
}
if (debCN.equals("Contact")) {
NodeList contact = party.item(partyIndex).getChildNodes();
setContact(new Contact(contact));
}
}
}
if (itemChilds.item(itemChildIndex).getLocalName().equals("SpecifiedTaxRegistration")) {
NodeList taxChilds = itemChilds.item(itemChildIndex).getChildNodes();
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
if (taxChilds.item(taxChildIndex).getLocalName() != null) {
if ((taxChilds.item(taxChildIndex).getLocalName().equals("ID"))) {
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID") != null) {
Node firstChild = taxChilds.item(taxChildIndex).getFirstChild();
if (firstChild != null) {
if (taxChilds.item(taxChildIndex).getAttributes()
.getNamedItem("schemeID").getNodeValue().equals("VA")) {
setVATID(firstChild.getNodeValue());
}
if (taxChilds.item(taxChildIndex).getAttributes()
.getNamedItem("schemeID").getNodeValue().equals("FC")) {
setTaxID(firstChild.getNodeValue());
}
}
if (debcurrentChild.equals("GlobalID")) {
if (nodes.item(nodeIndex).getAttributes().getNamedItem("schemeID") != null) {
SchemedID gid = new SchemedID().setScheme(nodes.item(nodeIndex).getAttributes().getNamedItem("schemeID").getNodeValue()).setId(nodes.item(nodeIndex).getTextContent());
addGlobalID(gid);
}
}
if (debcurrentChild.equals("DefinedTradeContact")) {
NodeList contact = nodes.item(nodeIndex).getChildNodes();
setContact(new Contact(contact));
}
if (debcurrentChild.equals("PostalTradeAddress")) {
NodeList postal = nodes.item(nodeIndex).getChildNodes();
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
if (postal.item(postalChildIndex).getLocalName() != null) {
if (postal.item(postalChildIndex).getLocalName().equals("LineOne")) {
setStreet(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("LineTwo")) {
setAdditionalAddress(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("LineThree")) {
setAdditionalAddressExtension(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("CityName")) {
setLocation(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("PostcodeCode")) {
setZIP(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("CountryID")) {
setCountry(postal.item(postalChildIndex).getTextContent());
}
}
}
}
if (debcurrentChild.equals("SpecifiedTaxRegistration")) {
NodeList taxChilds = nodes.item(nodeIndex).getChildNodes();
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
if (taxChilds.item(taxChildIndex).getLocalName() != null) {
if ((taxChilds.item(taxChildIndex).getLocalName().equals("ID"))) {
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID") != null) {
Node firstChild = taxChilds.item(taxChildIndex).getFirstChild();
if (firstChild != null) {
if (taxChilds.item(taxChildIndex).getAttributes()
.getNamedItem("schemeID").getNodeValue().equals("VA")) {
setVATID(firstChild.getNodeValue());
}
if (taxChilds.item(taxChildIndex).getAttributes()
.getNamedItem("schemeID").getNodeValue().equals("FC")) {
setTaxID(firstChild.getNodeValue());
}
}
}
}
}
}
}
}
}
@@ -284,15 +289,16 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
for (int nodeIndex = 0; nodeIndex < nodes.getLength(); nodeIndex++) {
//nodes.item(i).getTextContent())) {
String debLN = nodes.item(nodeIndex).getLocalName();
if (debLN.equals("Party")) {
// take one step back and parse from top
parseFromUBL(nodes);
return;
}
Node currentItemNode = nodes.item(nodeIndex);
NodeList itemChilds = currentItemNode.getChildNodes();
for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) {
if (itemChilds.item(itemChildIndex).getLocalName() != null) {
if (itemChilds.item(itemChildIndex).getLocalName().equals("Party")) {
parseFromUBL(nodes);
return;
}
if (itemChilds.item(itemChildIndex).getLocalName().equals("Name")) {
setName(itemChilds.item(itemChildIndex).getTextContent());
}
@@ -328,10 +334,8 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
if (postal.item(postalChildIndex).getLocalName().equals("CountryID")) {
setCountry(postal.item(postalChildIndex).getTextContent());
}
}
}
}
if (itemChilds.item(itemChildIndex).getLocalName().equals("URIUniversalCommunication")) {
NodeList URIchilds = itemChilds.item(itemChildIndex).getChildNodes();
@@ -419,8 +423,9 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
/***
* sets the email of the organization (not the one of the contact person)
* (while setEmail has to be defined here getEmail comes from IZUGFeRDExportableTradeParty)
* sets the email of the organization (not the one of the contact person)
* (while setEmail has to be defined here getEmail comes from IZUGFeRDExportableTradeParty)
* @param eMail address of institution (not contact)
* @return fluent setter
*/
public TradeParty setEmail(String eMail) {

View File

@@ -1,6 +1,7 @@
package org.mustangproject;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.AbstractList;
@@ -8,39 +9,47 @@ import java.util.Collections;
import java.util.List;
import java.util.RandomAccess;
import org.apache.commons.io.IOUtils;
import org.dom4j.io.XMLWriter;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class XMLTools extends XMLWriter {
@Override
public String escapeAttributeEntities(String s) {
public String escapeAttributeEntities(String s) {
return super.escapeAttributeEntities(s);
}
@Override
public String escapeElementEntities(String s) {
public String escapeElementEntities(String s) {
return super.escapeElementEntities(s);
}
public static List<Node> asList(NodeList n) {
return n.getLength()==0?
Collections.<Node>emptyList(): new NodeListWrapper(n);
return n.getLength() == 0 ?
Collections.<Node>emptyList() : new NodeListWrapper(n);
}
static final class NodeListWrapper extends AbstractList<Node>
implements RandomAccess {
private final NodeList list;
NodeListWrapper(NodeList l) {
list=l;
list = l;
}
public Node get(int index) {
@Override
public Node get(int index) {
return list.item(index);
}
public int size() {
@Override
public int size() {
return list.getLength();
}
}
public static String nDigitFormat(BigDecimal value, int scale) {
/*
* I needed 123,45, locale independent.I tried
@@ -63,9 +72,9 @@ public class XMLTools extends XMLWriter {
public static String encodeXML(CharSequence s) {
if (s == null) {
return "";
}
if (s == null) {
return "";
}
final StringBuilder sb = new StringBuilder();
final int len = s.length();
for (int i = 0; i < len; i++) {
@@ -112,36 +121,6 @@ public class XMLTools extends XMLWriter {
return sb.toString();
}
/**
* Returns the Byte Order Mark size and thus allows to skips over a BOM
* at the beginning of the given ByteArrayInputStream, if one exists.
*
* @param is the ByteArrayInputStream used
* @throws IOException if can not be read from is
* @see <a href="https://www.w3.org/TR/xml/#sec-guessing">Autodetection of Character Encodings</a>
*
public static int guessBOMSize(ByteArrayInputStream is) throws IOException {
byte[] pad = new byte[4];
is.read(pad);
is.reset();
int test2 = ((pad[0] & 0xFF) << 8) | (pad[1] & 0xFF);
int test3 = ((test2 & 0xFFFF) << 8) | (pad[2] & 0xFF);
int test4 = ((test3 & 0xFFFFFF) << 8) | (pad[3] & 0xFF);
//
if (test4 == 0x0000FEFF || test4 == 0xFFFE0000 || test4 == 0x0000FFFE || test4 == 0xFEFF0000) {
// UCS-4: BOM takes 4 bytes
return 4;
} else if (test3 == 0xEFBBFF) {
// UTF-8: BOM takes 3 bytes
return 3;
} else if (test2 == 0xFEFF || test2 == 0xFFFE) {
// UTF-16: BOM takes 2 bytes
return 2;
}
return 0;
}*/
/***
* removes utf8 byte order marks from byte arrays, in case one is there
* @param zugferdRaw the CII XML
@@ -149,6 +128,7 @@ public class XMLTools extends XMLWriter {
*/
public static byte[] removeBOM(byte[] zugferdRaw) {
final byte[] zugferdData;
// This handles the UTF-8 BOM
if ((zugferdRaw[0] == (byte) 0xEF) && (zugferdRaw[1] == (byte) 0xBB) && (zugferdRaw[2] == (byte) 0xBF)) {
// I don't like BOMs, lets remove it
zugferdData = new byte[zugferdRaw.length - 3];
@@ -159,5 +139,8 @@ public class XMLTools extends XMLWriter {
return zugferdData;
}
public static byte[] getBytesFromStream(InputStream fileinput) throws IOException {
return IOUtils.toByteArray (fileinput);
}
}

View File

@@ -22,18 +22,18 @@ package org.mustangproject.ZUGFeRD;
import static org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat.DATE;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.mustangproject.*;
import org.mustangproject.EStandard;
import org.mustangproject.FileAttachment;
import org.mustangproject.Invoice;
import org.mustangproject.XMLTools;
public class DAPullProvider extends ZUGFeRD2PullProvider implements IXMLProvider {
public class DAPullProvider extends ZUGFeRD2PullProvider {
protected IExportableTransaction trans;
private String paymentTermsDescription;
protected Profile profile = Profiles.getByName(EStandard.despatchadvice,"pilot", 1);
@@ -249,13 +249,9 @@ public class DAPullProvider extends ZUGFeRD2PullProvider implements IXMLProvider
+ "</SCRDMCCBDACIDAMessageStructure>";
final byte[] zugferdRaw;
try {
zugferdRaw = xml.getBytes("UTF-8");
zugferdRaw = xml.getBytes(StandardCharsets.UTF_8);
zugferdData = XMLTools.removeBOM(zugferdRaw);
} catch (final UnsupportedEncodingException e) {
Logger.getLogger(OXPullProvider.class.getName()).log(Level.SEVERE, null, e);
}
zugferdData = XMLTools.removeBOM(zugferdRaw);
}

View File

@@ -19,31 +19,35 @@
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 DXExporterFromA1 extends DXExporterFromA3 implements IZUGFeRDExporter {
import org.apache.pdfbox.preflight.PreflightDocument;
import org.apache.pdfbox.preflight.ValidationResult;
import org.apache.pdfbox.preflight.exception.ValidationException;
import org.apache.pdfbox.preflight.parser.PreflightParser;
import jakarta.activation.DataSource;
public class DXExporterFromA1 extends DXExporterFromA3 {
protected boolean ignorePDFAErrors = false;
public DXExporterFromA1 ignorePDFAErrors() {
@Override
public DXExporterFromA1 ignorePDFAErrors() {
this.ignorePDFAErrors = true;
return this;
}
private static boolean isValidA1(DataSource dataSource) throws IOException {
return getPDFAParserValidationResult(new PreflightParser(dataSource));
return getPDFAParserValidationResult(PreflightParserHelper.createPreflightParser (dataSource));
}
/***
* internal helper function: get namespace for order-x
* @param ver the delivery-x version
* @return the URN of the namespace
*/
public String getNamespaceForVersion(int ver) {
@Override
public String getNamespaceForVersion(int ver) {
// As of late 2022 the Delivery-X standard is not yet published. See specification:
// Die digitale Ablösung des Papier-Lieferscheins, Version 1.1, April 2022
// Chapter 7.1 XMP-Erweiterungsschema für PDF/A-3
@@ -55,7 +59,8 @@ public class DXExporterFromA1 extends DXExporterFromA3 implements IZUGFeRDExport
* @param ver the ox version
* @return the namespace prefix as string, without colon
*/
public String getPrefixForVersion(int ver) {
@Override
public String getPrefixForVersion(int ver) {
return "fx";
}
@@ -65,19 +70,19 @@ public class DXExporterFromA1 extends DXExporterFromA3 implements IZUGFeRDExport
* 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()) {
// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
try (PreflightDocument document = (PreflightDocument) parser.parse()) {
/*
* 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();
ValidationResult res = document.validate();
// Get validation result
return document.getResult().isValid();
return res.isValid();
} catch (ValidationException e) {
/*
* the parse method can throw a SyntaxValidationException if the PDF file can't
@@ -89,14 +94,17 @@ public class DXExporterFromA1 extends DXExporterFromA3 implements IZUGFeRDExport
}
public DXExporterFromA1 setProfile(Profile p) {
@Override
public DXExporterFromA1 setProfile(Profile p) {
return (DXExporterFromA1)super.setProfile(p);
}
public DXExporterFromA1 setProfile(String profileName) {
@Override
public DXExporterFromA1 setProfile(String profileName) {
return (DXExporterFromA1)super.setProfile(profileName);
}
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
@Override
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
throw new IOException("File is not a valid PDF/A input file");
}
@@ -108,32 +116,41 @@ public class DXExporterFromA1 extends DXExporterFromA3 implements IZUGFeRDExport
}
public DXExporterFromA1 load(String pdfFilename) throws IOException {
@Override
public DXExporterFromA1 load(String pdfFilename) throws IOException {
return (DXExporterFromA1) super.load(pdfFilename);
}
public DXExporterFromA1 load(byte[] pdfBinary) throws IOException {
@Override
public DXExporterFromA1 load(byte[] pdfBinary) throws IOException {
return (DXExporterFromA1) super.load(pdfBinary);
}
public DXExporterFromA1 load(InputStream pdfSource) throws IOException{
@Override
public DXExporterFromA1 load(InputStream pdfSource) throws IOException{
return (DXExporterFromA1) super.load(pdfSource);
}
public DXExporterFromA1 setCreator(String creator) {
@Override
public DXExporterFromA1 setCreator(String creator) {
return (DXExporterFromA1) super.setCreator(creator);
}
public DXExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
@Override
public DXExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
return (DXExporterFromA1) super.setConformanceLevel(newLevel);
}
public DXExporterFromA1 setProducer(String producer){
@Override
public DXExporterFromA1 setProducer(String producer){
return (DXExporterFromA1) super.setProducer(producer);
}
public DXExporterFromA1 setZUGFeRDVersion(int version){
@Override
public DXExporterFromA1 setZUGFeRDVersion(int version){
return (DXExporterFromA1) super.setZUGFeRDVersion(version);
}
public DXExporterFromA1 setXML(byte[] zugferdData) throws IOException{
@Override
public DXExporterFromA1 setXML(byte[] zugferdData) throws IOException{
return (DXExporterFromA1) super.setXML(zugferdData);
}
public DXExporterFromA1 disableAutoClose(boolean disableAutoClose){
@Override
public DXExporterFromA1 disableAutoClose(boolean disableAutoClose){
return (DXExporterFromA1) super.disableAutoClose(disableAutoClose);
}
public DXExporterFromA1 convertOnly() {

View File

@@ -20,16 +20,38 @@
*/
package org.mustangproject.ZUGFeRD;
import org.apache.pdfbox.cos.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.TransformerException;
import org.apache.pdfbox.Loader;
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.io.IOUtils;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
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.pdmodel.documentinterchange.logicalstructure.PDMarkInfo;
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.AdobePDFSchema;
import org.apache.xmpbox.schema.DublinCoreSchema;
@@ -43,16 +65,13 @@ import org.apache.xmpbox.xml.XmpSerializer;
import org.mustangproject.EStandard;
import org.mustangproject.FileAttachment;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.xml.transform.TransformerException;
import java.io.*;
import java.util.*;
import jakarta.activation.DataSource;
import jakarta.activation.FileDataSource;
public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<FileAttachment>();
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<>();
/**
* This flag controls whether or not the metadata is overwritten, or kind of merged.
@@ -108,9 +127,6 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
protected String despatchAdviceDocumentType = "DESPATCHADVICE";
private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
private boolean attachZUGFeRDHeaders = true;
/**
@@ -119,7 +135,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
*
* @param pdfFilename filename of an PDF/A1 compliant document
*/
public DXExporterFromA3 load(String pdfFilename) throws IOException {
@Override
public DXExporterFromA3 load(String pdfFilename) throws IOException {
ensurePDFIsValid(new FileDataSource(pdfFilename));
try (FileInputStream pdf = new FileInputStream(pdfFilename)) {
@@ -127,11 +144,13 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
}
}
public IXMLProvider getProvider() {
@Override
public IXMLProvider getProvider() {
return xmlProvider;
}
public DXExporterFromA3 setProfile(Profile p) {
@Override
public DXExporterFromA3 setProfile(Profile p) {
this.profile = p;
if (xmlProvider != null) {
xmlProvider.setProfile(p);
@@ -139,7 +158,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return this;
}
public DXExporterFromA3 setProfile(String profilename) {
@Override
public DXExporterFromA3 setProfile(String profilename) {
this.profile = Profiles.getByName(profilename);
if (xmlProvider != null) {
@@ -148,7 +168,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return this;
}
public DXExporterFromA3 addAdditionalFile(String name, byte[] content) {
@Override
public DXExporterFromA3 addAdditionalFile(String name, byte[] content) {
fileAttachments.add(new FileAttachment(name, "text/xml", "Supplement", content).setDescription("ZUGFeRD extension/additional data"));
return this;
}
@@ -161,9 +182,10 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
*
* @param pdfBinary binary of a PDF/A1 compliant document
*/
public DXExporterFromA3 load(byte[] pdfBinary) throws IOException {
@Override
public DXExporterFromA3 load(byte[] pdfBinary) throws IOException {
ensurePDFIsValid(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
doc = PDDocument.load(pdfBinary);
doc = Loader.loadPDF(pdfBinary);
return this;
}
@@ -171,11 +193,13 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
super();
}
public void attachFile(FileAttachment file) {
@Override
public void attachFile(FileAttachment file) {
fileAttachments.add(file);
}
public void attachFile(String filename, byte[] data, String mimetype, String relation) {
@Override
public void attachFile(String filename, byte[] data, String mimetype, String relation) {
FileAttachment fa = new FileAttachment(filename, mimetype, relation, data);
fileAttachments.add(fa);
}
@@ -185,7 +209,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* @param ZUGFeRDfilename the pdf file name
* @throws IOException if anything is wrong in the target location
*/
public void export(String ZUGFeRDfilename) throws IOException {
@Override
public void export(String ZUGFeRDfilename) throws IOException {
if (!documentPrepared) {
prepareDocument();
}
@@ -212,7 +237,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* @param output the OutputStream
* @throws IOException if anything is wrong in the OutputStream
*/
public void export(OutputStream output) throws IOException {
@Override
public void export(OutputStream output) throws IOException {
if (!documentPrepared) {
prepareDocument();
}
@@ -238,7 +264,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* @param data the binary data of the file/attachment
* @throws IOException if anything is wrong with filename
*/
public void PDFAttachGenericFile(String filename, String relationship, String description,
@Override
public void PDFAttachGenericFile(String filename, String relationship, String description,
String subType, byte[] data) throws IOException {
PDFAttachGenericFile(this.doc, filename, relationship, description, subType, data);
}
@@ -255,7 +282,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* @param data the binary data of the file/attachment
* @throws IOException if anything is wrong with filename
*/
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
@Override
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
String subType, byte[] data) throws IOException {
fileAttached = true;
@@ -274,7 +302,7 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
ef.setSize(data.length);
ef.setCreationDate(new GregorianCalendar());
ef.setModDate(GregorianCalendar.getInstance());
ef.setModDate(Calendar.getInstance());
fs.setEmbeddedFile(ef);
@@ -306,7 +334,7 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
doc.getDocumentCatalog().setNames(names);
// AF entry (Array) in catalog with the FileSpec
COSBase AFEntry = (COSBase) doc.getDocumentCatalog().getCOSObject().getItem("AF");
COSBase AFEntry = doc.getDocumentCatalog().getCOSObject().getItem("AF");
if ((AFEntry == null)) {
COSArray cosArray = new COSArray();
cosArray.add(fs);
@@ -332,7 +360,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* @param zugferdData XML data to be set as a byte array (XML file in raw form).
* @throws IOException (should not happen)
*/
public DXExporterFromA3 setXML(byte[] zugferdData) throws IOException {
@Override
public DXExporterFromA3 setXML(byte[] zugferdData) throws IOException {
CustomXMLProvider cus = new CustomXMLProvider();
// As of late 2022 the Delivery-X standard is not yet published. See specification:
// Die digitale Ablösung des Papier-Lieferscheins, Version 1.1, April 2022
@@ -353,11 +382,13 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
*
* @param pdfSource source to read a PDF/A1 compliant document from
*/
public DXExporterFromA3 load(InputStream pdfSource) throws IOException {
@Override
public DXExporterFromA3 load(InputStream pdfSource) throws IOException {
return load(readAllBytes(pdfSource));
}
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
@Override
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
return true;
}
@@ -380,23 +411,27 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* <p>
* Feel free to pass "A" as new level if you know what you are doing :-)
*/
public DXExporterFromA3 setConformanceLevel(PDFAConformanceLevel newLevel) {
@Override
public DXExporterFromA3 setConformanceLevel(PDFAConformanceLevel newLevel) {
conformanceLevel = newLevel;
return this;
}
public DXExporterFromA3 setCreator(String creator) {
@Override
public DXExporterFromA3 setCreator(String creator) {
this.creator = creator;
return this;
}
public DXExporterFromA3 setCreatorTool(String creatorTool) {
@Override
public DXExporterFromA3 setCreatorTool(String creatorTool) {
this.creatorTool = creatorTool;
return this;
}
public DXExporterFromA3 setProducer(String producer) {
@Override
public DXExporterFromA3 setProducer(String producer) {
this.producer = producer;
return this;
}
@@ -415,7 +450,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return this;
}
protected DXExporterFromA3 setAttachZUGFeRDHeaders(boolean attachHeaders) {
@Override
protected DXExporterFromA3 setAttachZUGFeRDHeaders(boolean attachHeaders) {
this.attachZUGFeRDHeaders = attachHeaders;
return this;
}
@@ -428,7 +464,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
*
* @param metadata the PDFbox XMPMetadata object
*/
protected void addXMP(XMPMetadata metadata) {
@Override
protected void addXMP(XMPMetadata metadata) {
if (attachZUGFeRDHeaders) {
// As of late 2022 the Delivery-X standard is not yet published. See specification:
@@ -459,12 +496,14 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
* @throws IOException if anything is wrong with already loaded PDF
*/
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
@Override
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
this.trans = trans;
return prepare();
}
public IExporter prepare() throws IOException {
@Override
public IExporter prepare() throws IOException {
prepareDocument();
xmlProvider.generateXML(trans);
String filename = "cida.xml";
@@ -483,7 +522,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* Reads the XMPMetadata from the PDDocument, if it exists.
* Otherwise creates XMPMetadata.
*/
protected XMPMetadata getXmpMetadata() throws IOException {
@Override
protected XMPMetadata getXmpMetadata() throws IOException {
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
if ((meta != null) && (meta.getLength() > 0)) {
try {
@@ -496,7 +536,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return XMPMetadata.createXMPMetadata();
}
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
@Override
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
new XmpSerializer().serialize(xmpMetadata, buffer, true); // see https://github.com/ZUGFeRD/mustangproject/issues/44
return buffer.toByteArray();
@@ -506,7 +547,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* Sets the producer if the overwrite flag is set or the producer is not already set.
* Sets the PDFVersion to 1.4 if the field is empty.
*/
protected void writeAdobePDFSchema(XMPMetadata xmp) {
@Override
protected void writeAdobePDFSchema(XMPMetadata xmp) {
AdobePDFSchema pdf = getAdobePDFSchema(xmp);
if (overwrite || isEmpty(pdf.getProducer()))
pdf.setProducer(producer);
@@ -516,7 +558,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* Returns the AdobePDFSchema from the XMPMetadata if it exists.
* If the overwrite flag is set or no AdobePDFSchema exists in the XMPMetadata, it is created, added and returned.
*/
protected AdobePDFSchema getAdobePDFSchema(XMPMetadata xmp) {
@Override
protected AdobePDFSchema getAdobePDFSchema(XMPMetadata xmp) {
AdobePDFSchema pdf = xmp.getAdobePDFSchema();
if (pdf != null)
if (overwrite)
@@ -526,7 +569,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return xmp.createAndAddAdobePDFSchema();
}
protected void writePDFAIdentificationSchema(XMPMetadata xmp) {
@Override
protected void writePDFAIdentificationSchema(XMPMetadata xmp) {
PDFAIdentificationSchema pdfaid = getPDFAIdentificationSchema(xmp);
if (overwrite || isEmpty(pdfaid.getConformance())) {
try {
@@ -541,17 +585,19 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
pdfaid.setPart(3);
}
protected PDFAIdentificationSchema getPDFAIdentificationSchema(XMPMetadata xmp) {
PDFAIdentificationSchema pdfaid = xmp.getPDFIdentificationSchema();
@Override
protected PDFAIdentificationSchema getPDFAIdentificationSchema(XMPMetadata xmp) {
PDFAIdentificationSchema pdfaid = xmp.getPDFAIdentificationSchema();
if (pdfaid != null)
if (overwrite)
xmp.removeSchema(pdfaid);
else
return pdfaid;
return xmp.createAndAddPFAIdentificationSchema();
return xmp.createAndAddPDFAIdentificationSchema();
}
protected void writeDublinCoreSchema(XMPMetadata xmp) {
@Override
protected void writeDublinCoreSchema(XMPMetadata xmp) {
DublinCoreSchema dc = getDublinCoreSchema(xmp);
if (dc.getFormat() == null)
dc.setFormat("application/pdf");
@@ -574,7 +620,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
}
}
protected DublinCoreSchema getDublinCoreSchema(XMPMetadata xmp) {
@Override
protected DublinCoreSchema getDublinCoreSchema(XMPMetadata xmp) {
DublinCoreSchema dc = xmp.getDublinCoreSchema();
if (dc != null)
if (overwrite)
@@ -584,15 +631,17 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return xmp.createAndAddDublinCoreSchema();
}
protected void writeXMLBasicSchema(XMPMetadata xmp) {
@Override
protected void writeXMLBasicSchema(XMPMetadata xmp) {
XMPBasicSchema xsb = getXmpBasicSchema(xmp);
if (overwrite || isEmpty(xsb.getCreatorTool()) || "UnknownApplication".equals(xsb.getCreatorTool()))
xsb.setCreatorTool(creatorTool);
if (overwrite || xsb.getCreateDate() == null)
xsb.setCreateDate(GregorianCalendar.getInstance());
xsb.setCreateDate(Calendar.getInstance());
}
protected XMPBasicSchema getXmpBasicSchema(XMPMetadata xmp) {
@Override
protected XMPBasicSchema getXmpBasicSchema(XMPMetadata xmp) {
XMPBasicSchema xsb = xmp.getXMPBasicSchema();
if (xsb != null)
if (overwrite)
@@ -602,7 +651,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return xmp.createAndAddXMPBasicSchema();
}
protected void writeDocumentInformation() {
@Override
protected void writeDocumentInformation() {
String fullProducer = producer + " (via mustangproject.org " + Version.VERSION + ")";
PDDocumentInformation info = doc.getDocumentInformation();
if (overwrite || info.getCreationDate() == null)
@@ -624,7 +674,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
/**
* Adds an OutputIntent and the sRGB color profile if no OutputIntent exist
*/
protected void addSRGBOutputIntend() throws IOException {
@Override
protected void addSRGBOutputIntend() throws IOException {
if (!doc.getDocumentCatalog().getOutputIntents().isEmpty()) {
return;
}
@@ -647,7 +698,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
/**
* Adds a MarkInfo element to the PDF if it doesn't already exist and sets it as marked.
*/
protected void setMarked() {
@Override
protected void setMarked() {
PDDocumentCatalog catalog = doc.getDocumentCatalog();
if (catalog.getMarkInfo() == null) {
catalog.setMarkInfo(new PDMarkInfo(doc.getPages().getCOSObject()));
@@ -658,7 +710,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
/**
* Adds a StructureTreeRoot element to the PDF if it doesn't already exist.
*/
protected void addStructureTreeRoot() {
@Override
protected void addStructureTreeRoot() {
if (doc.getDocumentCatalog().getStructureTreeRoot() == null) {
doc.getDocumentCatalog().setStructureTreeRoot(new PDStructureTreeRoot());
}
@@ -668,19 +721,22 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
/**
* @return if pdf file will be automatically closed after adding ZF
*/
public boolean isAutoCloseDisabled() {
@Override
public boolean isAutoCloseDisabled() {
return disableAutoClose;
}
/**
* @param disableAutoClose prevent PDF file from being closed after adding ZF
*/
public DXExporterFromA3 disableAutoClose(boolean disableAutoClose) {
@Override
public DXExporterFromA3 disableAutoClose(boolean disableAutoClose) {
this.disableAutoClose = disableAutoClose;
return this;
}
protected void setXMLProvider(IXMLProvider p) {
@Override
protected void setXMLProvider(IXMLProvider p) {
this.xmlProvider = p;
if (profile != null) {
xmlProvider.setProfile(profile);

View File

@@ -20,31 +20,10 @@
*/
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;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class EinLieferscheinExporter implements IExporter {
IXMLProvider xmlProvider;

View File

@@ -140,6 +140,11 @@ public interface IExportableTransaction {
return null;
}
default IZUGFeRDCashDiscount[] getCashDiscounts() { return null; }
/***
* @return the invoice line items with the positions
*/
IZUGFeRDExportableItem[] getZFItems();
/**

View File

@@ -18,7 +18,6 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;

View File

@@ -15,10 +15,10 @@
*/
package org.mustangproject.ZUGFeRD;
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
import java.math.BigDecimal;
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
/**
* The interface for allowances or charges, to be used by the pullprovider
* @author AlexanderSchmidt

View File

@@ -0,0 +1,18 @@
package org.mustangproject.ZUGFeRD;
public interface IZUGFeRDCashDiscount {
/***
* @return this particular cash discount as cross industry invoice XML
*/
public String getAsCII();
/***
* since EN16931 voted not to have (or even allow) cash discounts in their core invoice the german
* XRechnung CIUS defined it's own proprietary format for a freetext field
* @return this particular cash discount in proprietary xrechnung format
*/
public String getAsXRechnung();
}

View File

@@ -26,12 +26,13 @@ package org.mustangproject.ZUGFeRD;
* @author jstaerk
* */
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.mustangproject.Item;
import java.math.BigDecimal;
import java.util.Date;
import org.mustangproject.Item;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@JsonDeserialize(as = Item.class)
public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
IZUGFeRDExportableProduct getProduct();
@@ -140,6 +141,6 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
*/
default IZUGFeRDAllowanceCharge[] getItemTotalAllowances() {
return null;
};
}
}

View File

@@ -21,6 +21,7 @@
package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
import java.util.HashMap;
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
@@ -156,4 +157,12 @@ public interface IZUGFeRDExportableProduct {
}
return null;
}
default String getCountryOfOrigin() {
return null;
}
default HashMap<String, String> getAttributes() {
return null;
}
}

View File

@@ -20,8 +20,6 @@
*/
package org.mustangproject.ZUGFeRD;
import org.mustangproject.TradeParty;
/**
* Mustangproject's ZUGFeRD implementation neccessary interface for ZUGFeRD exporter Licensed under the APLv2
*

View File

@@ -18,11 +18,12 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import javax.activation.DataSource;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import jakarta.activation.DataSource;
public interface IZUGFeRDExporter extends Closeable, IExporter {
/**
* factory: loads a PDF file and returns an appropriate exporter

View File

@@ -18,11 +18,6 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import javax.activation.DataSource;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
public interface IZUGFeRDLegalOrganisation {
/***

View File

@@ -1,6 +1,7 @@
package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
import java.math.RoundingMode;
/***
* the linecalculator does the math within an item line, and e.g. calculates quantity*price.
@@ -40,7 +41,7 @@ public class LineCalculator {
priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159
price = priceGross.subtract(allowance).add(charge);
itemTotalNetAmount = currentItem.getQuantity().multiply(getPrice()).divide(currentItem.getBasisQuantity())
.subtract(allowanceItemTotal).setScale(2, BigDecimal.ROUND_HALF_UP);
.subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);
}

View File

@@ -19,31 +19,35 @@
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 OXExporterFromA1 extends OXExporterFromA3 implements IZUGFeRDExporter {
import org.apache.pdfbox.preflight.PreflightDocument;
import org.apache.pdfbox.preflight.ValidationResult;
import org.apache.pdfbox.preflight.exception.ValidationException;
import org.apache.pdfbox.preflight.parser.PreflightParser;
import jakarta.activation.DataSource;
public class OXExporterFromA1 extends OXExporterFromA3 {
protected boolean ignorePDFAErrors = false;
public OXExporterFromA1 ignorePDFAErrors() {
@Override
public OXExporterFromA1 ignorePDFAErrors() {
this.ignorePDFAErrors = true;
return this;
}
private static boolean isValidA1(DataSource dataSource) throws IOException {
return getPDFAParserValidationResult(new PreflightParser(dataSource));
return getPDFAParserValidationResult(PreflightParserHelper.createPreflightParser(dataSource));
}
/***
* internal helper function: get namespace for order-x
* @param ver the order-x version
* @return the URN of the namespace
*/
public String getNamespaceForVersion(int ver) {
@Override
public String getNamespaceForVersion(int ver) {
return "urn:factur-x:pdfa:CrossIndustryDocument:1p0#";
}
/***
@@ -51,7 +55,8 @@ public class OXExporterFromA1 extends OXExporterFromA3 implements IZUGFeRDExport
* @param ver the ox version
* @return the namespace prefix as string, without colon
*/
public String getPrefixForVersion(int ver) {
@Override
public String getPrefixForVersion(int ver) {
return "fx";
}
@@ -61,19 +66,19 @@ public class OXExporterFromA1 extends OXExporterFromA3 implements IZUGFeRDExport
* 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
// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
try (PreflightDocument document = parser.getPreflightDocument()) {
try (PreflightDocument document = (PreflightDocument) parser.parse()) {
/*
* 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();
ValidationResult res = document.validate();
// Get validation result
return document.getResult().isValid();
return res.isValid();
} catch (ValidationException e) {
/*
* the parse method can throw a SyntaxValidationException if the PDF file can't
@@ -85,14 +90,17 @@ public class OXExporterFromA1 extends OXExporterFromA3 implements IZUGFeRDExport
}
public OXExporterFromA1 setProfile(Profile p) {
@Override
public OXExporterFromA1 setProfile(Profile p) {
return (OXExporterFromA1)super.setProfile(p);
}
public OXExporterFromA1 setProfile(String profileName) {
@Override
public OXExporterFromA1 setProfile(String profileName) {
return (OXExporterFromA1)super.setProfile(profileName);
}
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
@Override
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
throw new IOException("File is not a valid PDF/A input file");
}
@@ -104,32 +112,41 @@ public class OXExporterFromA1 extends OXExporterFromA3 implements IZUGFeRDExport
}
public OXExporterFromA1 load(String pdfFilename) throws IOException {
@Override
public OXExporterFromA1 load(String pdfFilename) throws IOException {
return (OXExporterFromA1) super.load(pdfFilename);
}
public OXExporterFromA1 load(byte[] pdfBinary) throws IOException {
@Override
public OXExporterFromA1 load(byte[] pdfBinary) throws IOException {
return (OXExporterFromA1) super.load(pdfBinary);
}
public OXExporterFromA1 load(InputStream pdfSource) throws IOException{
@Override
public OXExporterFromA1 load(InputStream pdfSource) throws IOException{
return (OXExporterFromA1) super.load(pdfSource);
}
public OXExporterFromA1 setCreator(String creator) {
@Override
public OXExporterFromA1 setCreator(String creator) {
return (OXExporterFromA1) super.setCreator(creator);
}
public OXExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
@Override
public OXExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
return (OXExporterFromA1) super.setConformanceLevel(newLevel);
}
public OXExporterFromA1 setProducer(String producer){
@Override
public OXExporterFromA1 setProducer(String producer){
return (OXExporterFromA1) super.setProducer(producer);
}
public OXExporterFromA1 setZUGFeRDVersion(int version){
@Override
public OXExporterFromA1 setZUGFeRDVersion(int version){
return (OXExporterFromA1) super.setZUGFeRDVersion(version);
}
public OXExporterFromA1 setXML(byte[] zugferdData) throws IOException{
@Override
public OXExporterFromA1 setXML(byte[] zugferdData) throws IOException{
return (OXExporterFromA1) super.setXML(zugferdData);
}
public OXExporterFromA1 disableAutoClose(boolean disableAutoClose){
@Override
public OXExporterFromA1 disableAutoClose(boolean disableAutoClose){
return (OXExporterFromA1) super.disableAutoClose(disableAutoClose);
}
public OXExporterFromA1 convertOnly() {

View File

@@ -20,20 +20,38 @@
*/
package org.mustangproject.ZUGFeRD;
import org.apache.pdfbox.cos.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.TransformerException;
import org.apache.pdfbox.Loader;
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.io.IOUtils;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
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.pdmodel.documentinterchange.logicalstructure.PDMarkInfo;
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
import org.apache.pdfbox.pdmodel.font.PDCIDFontType2;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.AdobePDFSchema;
import org.apache.xmpbox.schema.DublinCoreSchema;
@@ -47,16 +65,13 @@ import org.apache.xmpbox.xml.XmpSerializer;
import org.mustangproject.EStandard;
import org.mustangproject.FileAttachment;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.xml.transform.TransformerException;
import java.io.*;
import java.util.*;
import jakarta.activation.DataSource;
import jakarta.activation.FileDataSource;
public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<FileAttachment>();
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<>();
/**
* This flag controls whether or not the metadata is overwritten, or kind of merged.
@@ -112,9 +127,6 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
protected String orderXDocumentType = "ORDER";
private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
private boolean attachZUGFeRDHeaders = true;
/**
@@ -123,7 +135,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
*
* @param pdfFilename filename of an PDF/A1 compliant document
*/
public OXExporterFromA3 load(String pdfFilename) throws IOException {
@Override
public OXExporterFromA3 load(String pdfFilename) throws IOException {
ensurePDFIsValid(new FileDataSource(pdfFilename));
try (FileInputStream pdf = new FileInputStream(pdfFilename)) {
@@ -131,11 +144,13 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
}
}
public IXMLProvider getProvider() {
@Override
public IXMLProvider getProvider() {
return xmlProvider;
}
public OXExporterFromA3 setProfile(Profile p) {
@Override
public OXExporterFromA3 setProfile(Profile p) {
this.profile = p;
if (xmlProvider != null) {
xmlProvider.setProfile(p);
@@ -143,7 +158,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return this;
}
public OXExporterFromA3 setProfile(String profilename) {
@Override
public OXExporterFromA3 setProfile(String profilename) {
this.profile = Profiles.getByName(profilename);
if (xmlProvider != null) {
@@ -152,7 +168,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return this;
}
public OXExporterFromA3 addAdditionalFile(String name, byte[] content) {
@Override
public OXExporterFromA3 addAdditionalFile(String name, byte[] content) {
fileAttachments.add(new FileAttachment(name, "text/xml", "Supplement", content).setDescription("ZUGFeRD extension/additional data"));
return this;
}
@@ -165,9 +182,10 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
*
* @param pdfBinary binary of a PDF/A1 compliant document
*/
public OXExporterFromA3 load(byte[] pdfBinary) throws IOException {
@Override
public OXExporterFromA3 load(byte[] pdfBinary) throws IOException {
ensurePDFIsValid(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
doc = PDDocument.load(pdfBinary);
doc = Loader.loadPDF(pdfBinary);
return this;
}
@@ -175,11 +193,13 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
super();
}
public void attachFile(FileAttachment file) {
@Override
public void attachFile(FileAttachment file) {
fileAttachments.add(file);
}
public void attachFile(String filename, byte[] data, String mimetype, String relation) {
@Override
public void attachFile(String filename, byte[] data, String mimetype, String relation) {
FileAttachment fa = new FileAttachment(filename, mimetype, relation, data);
fileAttachments.add(fa);
}
@@ -189,7 +209,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* @param ZUGFeRDfilename the pdf file name
* @throws IOException if anything is wrong in the target location
*/
public void export(String ZUGFeRDfilename) throws IOException {
@Override
public void export(String ZUGFeRDfilename) throws IOException {
if (!documentPrepared) {
prepareDocument();
}
@@ -216,7 +237,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* @param output the OutputStream
* @throws IOException if anything is wrong in the OutputStream
*/
public void export(OutputStream output) throws IOException {
@Override
public void export(OutputStream output) throws IOException {
if (!documentPrepared) {
prepareDocument();
}
@@ -242,7 +264,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* @param data the binary data of the file/attachment
* @throws java.io.IOException if anything is wrong with filename
*/
public void PDFAttachGenericFile(String filename, String relationship, String description,
@Override
public void PDFAttachGenericFile(String filename, String relationship, String description,
String subType, byte[] data) throws IOException {
PDFAttachGenericFile(this.doc, filename, relationship, description, subType, data);
}
@@ -259,7 +282,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* @param data the binary data of the file/attachment
* @throws IOException if anything is wrong with filename
*/
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
@Override
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
String subType, byte[] data) throws IOException {
fileAttached = true;
@@ -278,7 +302,7 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
ef.setSize(data.length);
ef.setCreationDate(new GregorianCalendar());
ef.setModDate(GregorianCalendar.getInstance());
ef.setModDate(Calendar.getInstance());
fs.setEmbeddedFile(ef);
@@ -310,7 +334,7 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
doc.getDocumentCatalog().setNames(names);
// AF entry (Array) in catalog with the FileSpec
COSBase AFEntry = (COSBase) doc.getDocumentCatalog().getCOSObject().getItem("AF");
COSBase AFEntry = doc.getDocumentCatalog().getCOSObject().getItem("AF");
if ((AFEntry == null)) {
COSArray cosArray = new COSArray();
cosArray.add(fs);
@@ -336,7 +360,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* @param zugferdData XML data to be set as a byte array (XML file in raw form).
* @throws IOException (should not happen)
*/
public OXExporterFromA3 setXML(byte[] zugferdData) throws IOException {
@Override
public OXExporterFromA3 setXML(byte[] zugferdData) throws IOException {
CustomXMLProvider cus = new CustomXMLProvider();
cus.setXML(zugferdData);
this.setXMLProvider(cus);
@@ -351,11 +376,13 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
*
* @param pdfSource source to read a PDF/A1 compliant document from
*/
public OXExporterFromA3 load(InputStream pdfSource) throws IOException {
@Override
public OXExporterFromA3 load(InputStream pdfSource) throws IOException {
return load(readAllBytes(pdfSource));
}
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
@Override
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
return true;
}
@@ -378,23 +405,27 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* <p>
* Feel free to pass "A" as new level if you know what you are doing :-)
*/
public OXExporterFromA3 setConformanceLevel(PDFAConformanceLevel newLevel) {
@Override
public OXExporterFromA3 setConformanceLevel(PDFAConformanceLevel newLevel) {
conformanceLevel = newLevel;
return this;
}
public OXExporterFromA3 setCreator(String creator) {
@Override
public OXExporterFromA3 setCreator(String creator) {
this.creator = creator;
return this;
}
public OXExporterFromA3 setCreatorTool(String creatorTool) {
@Override
public OXExporterFromA3 setCreatorTool(String creatorTool) {
this.creatorTool = creatorTool;
return this;
}
public OXExporterFromA3 setProducer(String producer) {
@Override
public OXExporterFromA3 setProducer(String producer) {
this.producer = producer;
return this;
}
@@ -413,7 +444,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return this;
}
protected OXExporterFromA3 setAttachZUGFeRDHeaders(boolean attachHeaders) {
@Override
protected OXExporterFromA3 setAttachZUGFeRDHeaders(boolean attachHeaders) {
this.attachZUGFeRDHeaders = attachHeaders;
return this;
}
@@ -426,7 +458,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
*
* @param metadata the PDFbox XMPMetadata object
*/
protected void addXMP(XMPMetadata metadata) {
@Override
protected void addXMP(XMPMetadata metadata) {
if (attachZUGFeRDHeaders) {
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, 1, true, xmlProvider.getProfile(),
@@ -453,12 +486,14 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
* @throws IOException if anything is wrong with already loaded PDF
*/
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
@Override
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
this.trans = trans;
return prepare();
}
public IExporter prepare() throws IOException {
@Override
public IExporter prepare() throws IOException {
prepareDocument();
xmlProvider.generateXML(trans);
String filename = "order-x.xml";
@@ -477,7 +512,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* Reads the XMPMetadata from the PDDocument, if it exists.
* Otherwise creates XMPMetadata.
*/
protected XMPMetadata getXmpMetadata() throws IOException {
@Override
protected XMPMetadata getXmpMetadata() throws IOException {
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
if ((meta != null) && (meta.getLength() > 0)) {
try {
@@ -490,7 +526,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return XMPMetadata.createXMPMetadata();
}
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
@Override
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
new XmpSerializer().serialize(xmpMetadata, buffer, true); // see https://github.com/ZUGFeRD/mustangproject/issues/44
return buffer.toByteArray();
@@ -500,7 +537,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* Sets the producer if the overwrite flag is set or the producer is not already set.
* Sets the PDFVersion to 1.4 if the field is empty.
*/
protected void writeAdobePDFSchema(XMPMetadata xmp) {
@Override
protected void writeAdobePDFSchema(XMPMetadata xmp) {
AdobePDFSchema pdf = getAdobePDFSchema(xmp);
if (overwrite || isEmpty(pdf.getProducer()))
pdf.setProducer(producer);
@@ -510,7 +548,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
* Returns the AdobePDFSchema from the XMPMetadata if it exists.
* If the overwrite flag is set or no AdobePDFSchema exists in the XMPMetadata, it is created, added and returned.
*/
protected AdobePDFSchema getAdobePDFSchema(XMPMetadata xmp) {
@Override
protected AdobePDFSchema getAdobePDFSchema(XMPMetadata xmp) {
AdobePDFSchema pdf = xmp.getAdobePDFSchema();
if (pdf != null)
if (overwrite)
@@ -520,7 +559,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return xmp.createAndAddAdobePDFSchema();
}
protected void writePDFAIdentificationSchema(XMPMetadata xmp) {
@Override
protected void writePDFAIdentificationSchema(XMPMetadata xmp) {
PDFAIdentificationSchema pdfaid = getPDFAIdentificationSchema(xmp);
if (overwrite || isEmpty(pdfaid.getConformance())) {
try {
@@ -535,17 +575,19 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
pdfaid.setPart(3);
}
protected PDFAIdentificationSchema getPDFAIdentificationSchema(XMPMetadata xmp) {
PDFAIdentificationSchema pdfaid = xmp.getPDFIdentificationSchema();
@Override
protected PDFAIdentificationSchema getPDFAIdentificationSchema(XMPMetadata xmp) {
PDFAIdentificationSchema pdfaid = xmp.getPDFAIdentificationSchema();
if (pdfaid != null)
if (overwrite)
xmp.removeSchema(pdfaid);
else
return pdfaid;
return xmp.createAndAddPFAIdentificationSchema();
return xmp.createAndAddPDFAIdentificationSchema();
}
protected void writeDublinCoreSchema(XMPMetadata xmp) {
@Override
protected void writeDublinCoreSchema(XMPMetadata xmp) {
DublinCoreSchema dc = getDublinCoreSchema(xmp);
if (dc.getFormat() == null)
dc.setFormat("application/pdf");
@@ -568,7 +610,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
}
}
protected DublinCoreSchema getDublinCoreSchema(XMPMetadata xmp) {
@Override
protected DublinCoreSchema getDublinCoreSchema(XMPMetadata xmp) {
DublinCoreSchema dc = xmp.getDublinCoreSchema();
if (dc != null)
if (overwrite)
@@ -578,15 +621,17 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return xmp.createAndAddDublinCoreSchema();
}
protected void writeXMLBasicSchema(XMPMetadata xmp) {
@Override
protected void writeXMLBasicSchema(XMPMetadata xmp) {
XMPBasicSchema xsb = getXmpBasicSchema(xmp);
if (overwrite || isEmpty(xsb.getCreatorTool()) || "UnknownApplication".equals(xsb.getCreatorTool()))
xsb.setCreatorTool(creatorTool);
if (overwrite || xsb.getCreateDate() == null)
xsb.setCreateDate(GregorianCalendar.getInstance());
xsb.setCreateDate(Calendar.getInstance());
}
protected XMPBasicSchema getXmpBasicSchema(XMPMetadata xmp) {
@Override
protected XMPBasicSchema getXmpBasicSchema(XMPMetadata xmp) {
XMPBasicSchema xsb = xmp.getXMPBasicSchema();
if (xsb != null)
if (overwrite)
@@ -596,7 +641,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
return xmp.createAndAddXMPBasicSchema();
}
protected void writeDocumentInformation() {
@Override
protected void writeDocumentInformation() {
String fullProducer = producer + " (via mustangproject.org " + Version.VERSION + ")";
PDDocumentInformation info = doc.getDocumentInformation();
if (overwrite || info.getCreationDate() == null)
@@ -618,7 +664,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
/**
* Adds an OutputIntent and the sRGB color profile if no OutputIntent exist
*/
protected void addSRGBOutputIntend() throws IOException {
@Override
protected void addSRGBOutputIntend() throws IOException {
if (!doc.getDocumentCatalog().getOutputIntents().isEmpty()) {
return;
}
@@ -641,7 +688,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
/**
* Adds a MarkInfo element to the PDF if it doesn't already exist and sets it as marked.
*/
protected void setMarked() {
@Override
protected void setMarked() {
PDDocumentCatalog catalog = doc.getDocumentCatalog();
if (catalog.getMarkInfo() == null) {
catalog.setMarkInfo(new PDMarkInfo(doc.getPages().getCOSObject()));
@@ -652,7 +700,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
/**
* Adds a StructureTreeRoot element to the PDF if it doesn't already exist.
*/
protected void addStructureTreeRoot() {
@Override
protected void addStructureTreeRoot() {
if (doc.getDocumentCatalog().getStructureTreeRoot() == null) {
doc.getDocumentCatalog().setStructureTreeRoot(new PDStructureTreeRoot());
}
@@ -662,19 +711,22 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
/**
* @return if pdf file will be automatically closed after adding ZF
*/
public boolean isAutoCloseDisabled() {
@Override
public boolean isAutoCloseDisabled() {
return disableAutoClose;
}
/**
* @param disableAutoClose prevent PDF file from being closed after adding ZF
*/
public OXExporterFromA3 disableAutoClose(boolean disableAutoClose) {
@Override
public OXExporterFromA3 disableAutoClose(boolean disableAutoClose) {
this.disableAutoClose = disableAutoClose;
return this;
}
protected void setXMLProvider(IXMLProvider p) {
@Override
protected void setXMLProvider(IXMLProvider p) {
this.xmlProvider = p;
if (profile != null) {
xmlProvider.setProfile(profile);

View File

@@ -22,26 +22,19 @@ package org.mustangproject.ZUGFeRD;
import static org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat.DATE;
import static org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants.CORRECTEDINVOICE;
import static org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants.CATEGORY_CODES_WITH_EXEMPTION_REASON;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.mustangproject.EStandard;
import org.mustangproject.FileAttachment;
import org.mustangproject.IncludedNote;
import org.mustangproject.XMLTools;
public class OXPullProvider extends ZUGFeRD2PullProvider implements IXMLProvider {
public class OXPullProvider extends ZUGFeRD2PullProvider {
protected IExportableTransaction trans;
protected TransactionCalculator calc;
@@ -333,17 +326,19 @@ public class OXPullProvider extends ZUGFeRD2PullProvider implements IXMLProvider
}
}
}
if ((trans.getDocumentCode() == CORRECTEDINVOICE)/*||(trans.getDocumentCode() == DocumentCodeTypeConstants.CREDITNOTE)*/) {
hasDueDate = false;
if (trans.getDocumentCode() != null) {
if ((trans.getDocumentCode().equals(CORRECTEDINVOICE))/*||(trans.getDocumentCode().equals (DocumentCodeTypeConstants.CREDITNOTE))*/) {
hasDueDate = false;
}
}
final Map<BigDecimal, VATAmount> VATPercentAmountMap = calc.getVATPercentAmountMap();
for (final BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
final VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
if (amount != null) {
final String amountCategoryCode = amount.getCategoryCode();
/*final String amountCategoryCode = amount.getCategoryCode();
final boolean displayExemptionReason = CATEGORY_CODES_WITH_EXEMPTION_REASON.contains(amountCategoryCode);
/* xml += "<ram:ApplicableTradeTax>\n"
xml += "<ram:ApplicableTradeTax>\n"
+ "<ram:CalculatedAmount>" + currencyFormat(amount.getCalculated())
+ "</ram:CalculatedAmount>\n" //currencyID=\"EUR\"
+ "<ram:TypeCode>VAT</ram:TypeCode>\n"
@@ -479,13 +474,9 @@ public class OXPullProvider extends ZUGFeRD2PullProvider implements IXMLProvider
+ "</rsm:SCRDMCCBDACIOMessageStructure>";
final byte[] zugferdRaw;
try {
zugferdRaw = xml.getBytes("UTF-8");
zugferdRaw = xml.getBytes(StandardCharsets.UTF_8);
zugferdData = XMLTools.removeBOM(zugferdRaw);
} catch (final UnsupportedEncodingException e) {
Logger.getLogger(OXPullProvider.class.getName()).log(Level.SEVERE, null, e);
}
zugferdData = XMLTools.removeBOM(zugferdRaw);
}

View File

@@ -0,0 +1,99 @@
package org.mustangproject.ZUGFeRD;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.preflight.parser.PreflightParser;
import jakarta.activation.DataSource;
// Copied from PDFBox preflight 2.0.x
final class ByteArrayDataSource implements DataSource
{
private ByteArrayOutputStream data;
private String type = null;
private String name = null;
public ByteArrayDataSource (InputStream is) throws IOException
{
data = new ByteArrayOutputStream ();
IOUtils.copy (is, data);
IOUtils.closeQuietly (is);
}
public String getContentType ()
{
return this.type;
}
/**
* @param type
* the type to set
*/
public void setType (String type)
{
this.type = type;
}
/**
* @param name
* the name to set
*/
public void setName (String name)
{
this.name = name;
}
public InputStream getInputStream () throws IOException
{
return new ByteArrayInputStream (data.toByteArray ());
}
public String getName ()
{
return this.name;
}
public OutputStream getOutputStream () throws IOException
{
this.data = new ByteArrayOutputStream ();
return data;
}
}
// Try to create an API similar to the 2.x one
final class PreflightParserHelper
{
private static File createTmpFile (InputStream input) throws IOException
{
FileOutputStream fos = null;
try
{
File tmpFile = File.createTempFile ("mustang-pdf", ".pdf");
fos = new FileOutputStream (tmpFile);
IOUtils.copy (input, fos);
return tmpFile;
}
finally
{
IOUtils.closeQuietly (input);
IOUtils.closeQuietly (fos);
}
}
public static PreflightParser createPreflightParser (DataSource dataSource) throws IOException
{
return new PreflightParser (createTmpFile (dataSource.getInputStream ()));
}
}
final class PDFBoxUpdateMitigation
{
// Dummy for the name only
}

View File

@@ -20,12 +20,12 @@
*/
package org.mustangproject.ZUGFeRD;
import org.mustangproject.EStandard;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.mustangproject.EStandard;
public class Profiles {
static Map<String, Profile> zf2Map = Stream.of(new Object[][]{
{"MINIMUM", new Profile("MINIMUM", "urn:factur-x.eu:1p0:minimum")},

View File

@@ -20,33 +20,23 @@
*/
package org.mustangproject.ZUGFeRD;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.mustangproject.EStandard;
import org.mustangproject.FileAttachment;
import org.mustangproject.TradeParty;
import org.mustangproject.XMLTools;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat.DATE;
import static org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants.CORRECTEDINVOICE;
import static org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants.CATEGORY_CODES_WITH_EXEMPTION_REASON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UBLDAPullProvider implements IXMLProvider {
private static final Logger LOGGER = LoggerFactory.getLogger (UBLDAPullProvider.class);
protected IExportableTransaction trans;
protected TransactionCalculator calc;
@@ -96,13 +86,9 @@ public class UBLDAPullProvider implements IXMLProvider {
}
xml += "</DespatchAdvice>\n";
final byte[] ublRaw;
try {
ublRaw = xml.getBytes("UTF-8");
ublRaw = xml.getBytes(StandardCharsets.UTF_8);
ublData = XMLTools.removeBOM(ublRaw);
} catch (final UnsupportedEncodingException e) {
Logger.getLogger(UBLDAPullProvider.class.getName()).log(Level.SEVERE, null, e);
}
ublData = XMLTools.removeBOM(ublRaw);
}
public String getPartyXML(IZUGFeRDExportableTradeParty tp) {
@@ -133,7 +119,7 @@ public class UBLDAPullProvider implements IXMLProvider {
try {
document = DocumentHelper.parseText(new String(ublData));
} catch (final DocumentException e1) {
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e1);
LOGGER.error ("Failed to parse UBL", e1);
}
try {
final OutputFormat format = OutputFormat.createPrettyPrint();
@@ -143,7 +129,7 @@ public class UBLDAPullProvider implements IXMLProvider {
res = sw.toString().getBytes(StandardCharsets.UTF_8);
} catch (final IOException e) {
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e);
LOGGER.error ("Failed to write XML", e);
}
return res;

View File

@@ -1,9 +1,20 @@
package org.mustangproject.ZUGFeRD;
import javax.xml.transform.*;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
/***
@@ -31,9 +42,8 @@ public class XMLUpgrader {
* @return String the updated XML
* @throws FileNotFoundException if the source could not be found
* @throws TransformerException if the source could not be transformed
* @throws UnsupportedEncodingException if the source was not utf8
*/
public String migrateFromV1ToV2(String xmlFilename) throws FileNotFoundException, TransformerException, UnsupportedEncodingException {
public String migrateFromV1ToV2(String xmlFilename) throws FileNotFoundException, TransformerException {
/**
* *
* http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf
@@ -45,7 +55,7 @@ public class XMLUpgrader {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
applySchematronXsl(new FileInputStream(xmlFilename), baos);
String res = null;
res = baos.toString("UTF-8");
res = baos.toString(StandardCharsets.UTF_8);
return res;
}

View File

@@ -30,7 +30,15 @@ package org.mustangproject.ZUGFeRD;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.XmpConstants;
import org.apache.xmpbox.schema.PDFAExtensionSchema;
import org.apache.xmpbox.type.*;
import org.apache.xmpbox.type.ArrayProperty;
import org.apache.xmpbox.type.Attribute;
import org.apache.xmpbox.type.Cardinality;
import org.apache.xmpbox.type.ChoiceType;
import org.apache.xmpbox.type.DefinedStructuredType;
import org.apache.xmpbox.type.PDFAPropertyType;
import org.apache.xmpbox.type.PDFASchemaType;
import org.apache.xmpbox.type.StructuredType;
import org.apache.xmpbox.type.TextType;
import org.mustangproject.EStandard;
/**

View File

@@ -20,31 +20,10 @@
*/
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;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class XRExporter implements IExporter {
IXMLProvider xmlProvider;

View File

@@ -1,21 +1,54 @@
package org.mustangproject.ZUGFeRD;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.mustangproject.XMLTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class XRechnungImporter extends ZUGFeRDImporter {
private static final Logger LOGGER = LoggerFactory.getLogger (XRechnungImporter.class);
public XRechnungImporter(byte[] rawXml) {
super();
public XRechnungImporter(byte[] rawXml) {
super();
try {
setRawXML(rawXml);
containsMeta = true;
} catch (final IOException e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
throw new ZUGFeRDExportException(e);
try {
setRawXML(rawXml);
containsMeta = true;
} catch (final IOException e) {
LOGGER.error ("Failed to set raw XML", e);
throw new ZUGFeRDExportException(e);
}
}
}
public XRechnungImporter(String filename) {
super();
try {
setRawXML(Files.readAllBytes(Paths.get(filename)));
containsMeta = true;
} catch (final IOException e) {
LOGGER.error ("Failed to set raw XML", e);
throw new ZUGFeRDExportException(e);
}
}
public XRechnungImporter(InputStream fileinput) {
super();
try {
setRawXML(XMLTools.getBytesFromStream(fileinput));
containsMeta = true;
} catch (final IOException e) {
LOGGER.error ("Failed to set raw XML", e);
throw new ZUGFeRDExportException(e);
}
}
}

View File

@@ -30,8 +30,6 @@ import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
@@ -39,9 +37,11 @@ import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.mustangproject.XMLTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLProvider {
public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider {
private static final Logger LOGGER = LoggerFactory.getLogger (ZUGFeRD1PullProvider.class);
//// MAIN CLASS
@@ -93,17 +93,17 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr
try {
document = DocumentHelper.parseText(new String(zugferdData));
} catch (final DocumentException e1) {
Logger.getLogger(ZUGFeRD1PullProvider.class.getName()).log(Level.SEVERE, null, e1);
LOGGER.error ("Failed to parse ZUGFeRD data", e1);
}
try {
final OutputFormat format = OutputFormat.createPrettyPrint();
format.setTrimText(false);
final XMLWriter writer = new XMLWriter(sw, format);
writer.write(document);
res = sw.toString().getBytes("UTF-8");
res = sw.toString().getBytes(StandardCharsets.UTF_8);
} catch (final IOException e) {
Logger.getLogger(ZUGFeRD1PullProvider.class.getName()).log(Level.SEVERE, null, e);
LOGGER.error ("Failed to write ZUGFeRD data", e);
}
return res;

View File

@@ -25,7 +25,6 @@ import static org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants.CATE
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
@@ -35,9 +34,8 @@ import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.dom4j.Document;
@@ -49,8 +47,11 @@ import org.mustangproject.FileAttachment;
import org.mustangproject.IncludedNote;
import org.mustangproject.XMLTools;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ZUGFeRD2PullProvider implements IXMLProvider {
private static final Logger LOGGER = LoggerFactory.getLogger (ZUGFeRD2PullProvider.class);
protected byte[] zugferdData;
protected IExportableTransaction trans;
@@ -92,7 +93,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
try {
document = DocumentHelper.parseText(new String(zugferdData));
} catch (final DocumentException e1) {
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e1);
LOGGER.error ("Failed to parse ZUGFeRD data", e1);
}
try {
final OutputFormat format = OutputFormat.createPrettyPrint();
@@ -102,7 +103,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
res = sw.toString().getBytes(StandardCharsets.UTF_8);
} catch (final IOException e) {
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e);
LOGGER.error ("Failed to write ZUGFeRD data", e);
}
return res;
@@ -290,11 +291,21 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
paymentTermsDescription = XMLTools.encodeXML(trans.getPaymentTermDescription());
}
if ((paymentTermsDescription == null) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CORRECTEDINVOICE) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)) {
paymentTermsDescription = "Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate());
if ((profile == Profiles.getByName("XRechnung")) && (trans.getCashDiscounts() != null) && (trans.getCashDiscounts().length > 0)) {
for (IZUGFeRDCashDiscount discount : trans.getCashDiscounts()
) {
if (paymentTermsDescription == null) {
paymentTermsDescription = "";
}
paymentTermsDescription += discount.getAsXRechnung();
}
} else if ((paymentTermsDescription == null) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CORRECTEDINVOICE) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)) {
paymentTermsDescription = "Please remit until " + germanDateFormat.format(trans.getDueDate());
}
String typecode = "380";
if (trans.getDocumentCode() != null) {
typecode = trans.getDocumentCode();
@@ -387,6 +398,19 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
XMLTools.encodeXML(currentItem.getProduct().getDescription()) +
"</ram:Description>";
}
if (currentItem.getProduct().getAttributes() != null) {
for ( Entry<String, String> entry : currentItem.getProduct().getAttributes().entrySet() ) {
xml += "<ram:ApplicableProductCharacteristic>" +
"<ram:Description>" + XMLTools.encodeXML(entry.getKey()) + "</ram:Description>" +
"<ram:Value>" + XMLTools.encodeXML(entry.getValue()) + "</ram:Value>" +
"</ram:ApplicableProductCharacteristic>";
}
}
if (currentItem.getProduct().getCountryOfOrigin() != null) {
xml += "<ram:OriginTradeCountry><ram:ID>" +
XMLTools.encodeXML(currentItem.getProduct().getCountryOfOrigin()) +
"</ram:ID></ram:OriginTradeCountry>";
}
xml += "</ram:SpecifiedTradeProduct>"
+ "<ram:SpecifiedLineTradeAgreement>";
@@ -404,19 +428,23 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ "<ram:LineID>" + XMLTools.encodeXML(currentItem.getBuyerOrderReferencedDocumentLineID()) + "</ram:LineID>"
+ "</ram:BuyerOrderReferencedDocument>";
}
xml += "<ram:GrossPriceProductTradePrice>"
+ "<ram:ChargeAmount>" + priceFormat(lc.getPriceGross())
+ "</ram:ChargeAmount>" //currencyID=\"EUR\"
+ "<ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit())
+ "\">" + quantityFormat(currentItem.getBasisQuantity()) + "</ram:BasisQuantity>"
+ allowanceChargeStr
// + " <AppliedTradeAllowanceCharge>"
// + " <ChargeIndicator>false</ChargeIndicator>"
// + " <ActualAmount currencyID=\"EUR\">0.6667</ActualAmount>"
// + " <Reason>Rabatt</Reason>"
// + " </AppliedTradeAllowanceCharge>"
+ "</ram:GrossPriceProductTradePrice>"
+ "<ram:NetPriceProductTradePrice>"
if (!allowanceChargeStr.isEmpty()) {
xml += "<ram:GrossPriceProductTradePrice>"
+ "<ram:ChargeAmount>" + priceFormat(lc.getPriceGross())
+ "</ram:ChargeAmount>" //currencyID=\"EUR\"
+ "<ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit())
+ "\">" + quantityFormat(currentItem.getBasisQuantity()) + "</ram:BasisQuantity>"
+ allowanceChargeStr
// + " <AppliedTradeAllowanceCharge>"
// + " <ChargeIndicator>false</ChargeIndicator>"
// + " <ActualAmount currencyID=\"EUR\">0.6667</ActualAmount>"
// + " <Reason>Rabatt</Reason>"
// + " </AppliedTradeAllowanceCharge>"
+ "</ram:GrossPriceProductTradePrice>";
}
xml += "<ram:NetPriceProductTradePrice>"
+ "<ram:ChargeAmount>" + priceFormat(lc.getPrice())
+ "</ram:ChargeAmount>" // currencyID=\"EUR\"
+ "<ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit())
@@ -536,10 +564,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
xml += "</ram:OccurrenceDateTime>";
xml += " </ram:ActualDeliverySupplyChainEvent>";
} else {
if ((trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE) && (getProfile() != Profiles.getByName("Minimum"))) {
throw new IllegalStateException("No delivery date provided");
}
}
/*
* + "<DeliveryNoteReferencedDocument>" +
@@ -685,6 +709,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
} else {
xml += buildPaymentTermsXml();
}
if ((profile == Profiles.getByName("Extended")) && (trans.getCashDiscounts() != null) && (trans.getCashDiscounts().length > 0)) {
for (IZUGFeRDCashDiscount discount : trans.getCashDiscounts()
) {
xml += discount.getAsCII();
}
}
final String allowanceTotalLine = "<ram:AllowanceTotalAmount>" + currencyFormat(calc.getAllowancesForPercent(null)) + "</ram:AllowanceTotalAmount>";
@@ -736,13 +766,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ "</rsm:CrossIndustryInvoice>";
final byte[] zugferdRaw;
try {
zugferdRaw = xml.getBytes("UTF-8");
zugferdRaw = xml.getBytes(StandardCharsets.UTF_8);
zugferdData = XMLTools.removeBOM(zugferdRaw);
} catch (final UnsupportedEncodingException e) {
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e);
}
zugferdData = XMLTools.removeBOM(zugferdRaw);
}
protected String buildItemNotes(IZUGFeRDExportableItem currentItem) {

View File

@@ -19,25 +19,21 @@
package org.mustangproject.ZUGFeRD;
import java.io.IOException;
import java.io.InputStream;
import org.apache.pdfbox.preflight.PreflightDocument;
import org.apache.pdfbox.preflight.ValidationResult;
import org.apache.pdfbox.preflight.exception.ValidationException;
import org.apache.pdfbox.preflight.parser.PreflightParser;
import org.mustangproject.EStandard;
import javax.activation.DataSource;
import java.io.IOException;
import java.io.InputStream;
import jakarta.activation.DataSource;
public class ZUGFeRDExporterFromA1 extends ZUGFeRDExporterFromA3 implements IZUGFeRDExporter {
protected boolean ignorePDFAErrors = false;
public ZUGFeRDExporterFromA1 ignorePDFAErrors() {
this.ignorePDFAErrors = true;
return this;
}
public class ZUGFeRDExporterFromA1 extends ZUGFeRDExporterFromA3 {
private static boolean isValidA1(DataSource dataSource) throws IOException {
return getPDFAParserValidationResult(new PreflightParser(dataSource));
return getPDFAParserValidationResult(PreflightParserHelper.createPreflightParser(dataSource));
}
private static boolean getPDFAParserValidationResult(PreflightParser parser) throws IOException {
@@ -46,19 +42,19 @@ public class ZUGFeRDExporterFromA1 extends ZUGFeRDExporterFromA3 implements IZUG
* 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
// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
try (PreflightDocument document = parser.getPreflightDocument()) {
try (PreflightDocument document = (PreflightDocument) parser.parse()) {
/*
* 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();
ValidationResult res = document.validate();
// Get validation result
return document.getResult().isValid();
return res.isValid();
} catch (ValidationException e) {
/*
* the parse method can throw a SyntaxValidationException if the PDF file can't
@@ -70,14 +66,17 @@ public class ZUGFeRDExporterFromA1 extends ZUGFeRDExporterFromA3 implements IZUG
}
public ZUGFeRDExporterFromA1 setProfile(Profile p) {
@Override
public ZUGFeRDExporterFromA1 setProfile(Profile p) {
return (ZUGFeRDExporterFromA1)super.setProfile(p);
}
public ZUGFeRDExporterFromA1 setProfile(String profileName) {
@Override
public ZUGFeRDExporterFromA1 setProfile(String profileName) {
return (ZUGFeRDExporterFromA1)super.setProfile(profileName);
}
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
@Override
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
throw new IOException("File is not a valid PDF/A-1 input file");
}
@@ -85,35 +84,45 @@ public class ZUGFeRDExporterFromA1 extends ZUGFeRDExporterFromA3 implements IZUG
}
public ZUGFeRDExporterFromA1 load(String pdfFilename) throws IOException {
@Override
public ZUGFeRDExporterFromA1 load(String pdfFilename) throws IOException {
return (ZUGFeRDExporterFromA1) super.load(pdfFilename);
}
public ZUGFeRDExporterFromA1 load(byte[] pdfBinary) throws IOException {
@Override
public ZUGFeRDExporterFromA1 load(byte[] pdfBinary) throws IOException {
return (ZUGFeRDExporterFromA1) super.load(pdfBinary);
}
public ZUGFeRDExporterFromA1 load(InputStream pdfSource) throws IOException{
@Override
public ZUGFeRDExporterFromA1 load(InputStream pdfSource) throws IOException{
return (ZUGFeRDExporterFromA1) super.load(pdfSource);
}
public ZUGFeRDExporterFromA1 setCreator(String creator) {
@Override
public ZUGFeRDExporterFromA1 setCreator(String creator) {
return (ZUGFeRDExporterFromA1) super.setCreator(creator);
}
public ZUGFeRDExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
@Override
public ZUGFeRDExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
return (ZUGFeRDExporterFromA1) super.setConformanceLevel(newLevel);
}
public ZUGFeRDExporterFromA1 setProducer(String producer){
@Override
public ZUGFeRDExporterFromA1 setProducer(String producer){
return (ZUGFeRDExporterFromA1) super.setProducer(producer);
}
public ZUGFeRDExporterFromA1 setZUGFeRDVersion(EStandard est, int version){
@Override
public ZUGFeRDExporterFromA1 setZUGFeRDVersion(EStandard est, int version){
return (ZUGFeRDExporterFromA1) super.setZUGFeRDVersion(est, version);
}
public ZUGFeRDExporterFromA1 setZUGFeRDVersion(int version){
@Override
public ZUGFeRDExporterFromA1 setZUGFeRDVersion(int version){
return (ZUGFeRDExporterFromA1) super.setZUGFeRDVersion(version);
}
public ZUGFeRDExporterFromA1 setXML(byte[] zugferdData) throws IOException{
@Override
public ZUGFeRDExporterFromA1 setXML(byte[] zugferdData) throws IOException{
return (ZUGFeRDExporterFromA1) super.setXML(zugferdData);
}
public ZUGFeRDExporterFromA1 disableAutoClose(boolean disableAutoClose){
@Override
public ZUGFeRDExporterFromA1 disableAutoClose(boolean disableAutoClose){
return (ZUGFeRDExporterFromA1) super.disableAutoClose(disableAutoClose);
}
public ZUGFeRDExporterFromA1 convertOnly() {

View File

@@ -20,9 +20,35 @@
*/
package org.mustangproject.ZUGFeRD;
import org.apache.pdfbox.cos.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.TransformerException;
import org.apache.pdfbox.Loader;
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.io.IOUtils;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdfwriter.compress.CompressParameters;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
@@ -33,7 +59,6 @@ import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
import org.apache.xmpbox.XMPMetadata;
import org.apache.xmpbox.schema.AdobePDFSchema;
import org.apache.xmpbox.schema.DublinCoreSchema;
@@ -47,19 +72,21 @@ import org.apache.xmpbox.xml.XmpSerializer;
import org.mustangproject.EStandard;
import org.mustangproject.FileAttachment;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.xml.transform.TransformerException;
import java.io.*;
import java.util.*;
import jakarta.activation.DataSource;
import jakarta.activation.FileDataSource;
public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporter, IExporter, Closeable {
public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporter {
private boolean isFacturX = true;
public static final int DefaultZUGFeRDVersion = 2;
protected boolean ignorePDFAErrors = false;
public ZUGFeRDExporterFromA3 ignorePDFAErrors() {
this.ignorePDFAErrors = true;
return this;
}
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<FileAttachment>();
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<>();
/**
* This flag controls whether or not the metadata is overwritten, or kind of merged.
@@ -111,9 +138,6 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
protected PDDocument doc;
private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
protected int ZFVersion = DefaultZUGFeRDVersion;
private boolean attachZUGFeRDHeaders = true;
@@ -220,9 +244,10 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
* Generate ZF2.1 files with filename factur-x.xml
*
* @return this (fluent setter)
* @deprecated
* @deprecated It's now the default anyway
*/
public ZUGFeRDExporterFromA3 setFacturX() {
@Deprecated
public ZUGFeRDExporterFromA3 setFacturX() {
isFacturX = true;
return this;
}
@@ -258,7 +283,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
*/
public ZUGFeRDExporterFromA3 load(byte[] pdfBinary) throws IOException {
ensurePDFIsValid(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
doc = PDDocument.load(pdfBinary);
doc = Loader.loadPDF(pdfBinary);
return this;
}
@@ -282,7 +307,8 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
* @param ZUGFeRDfilename the pdf file name
* @throws IOException if anything is wrong in the target location
*/
public void export(String ZUGFeRDfilename) throws IOException {
@Override
public void export(String ZUGFeRDfilename) throws IOException {
if (!documentPrepared) {
prepareDocument();
}
@@ -290,7 +316,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
throw new IOException(
"File must be attached (usually with setTransaction) before perfoming this operation");
}
doc.save(ZUGFeRDfilename);
doc.save(ZUGFeRDfilename, CompressParameters.NO_COMPRESSION);
if (!disableAutoClose) {
close();
}
@@ -309,7 +335,8 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
* @param output the OutputStream
* @throws IOException if anything is wrong in the OutputStream
*/
public void export(OutputStream output) throws IOException {
@Override
public void export(OutputStream output) throws IOException {
if (!documentPrepared) {
prepareDocument();
}
@@ -317,7 +344,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
throw new IOException(
"File must be attached (usually with setTransaction) before perfoming this operation");
}
doc.save(output);
doc.save(output, CompressParameters.NO_COMPRESSION);
if (!disableAutoClose) {
close();
}
@@ -371,7 +398,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
ef.setSize(data.length);
ef.setCreationDate(new GregorianCalendar());
ef.setModDate(GregorianCalendar.getInstance());
ef.setModDate(Calendar.getInstance());
fs.setEmbeddedFile(ef);
@@ -403,7 +430,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
doc.getDocumentCatalog().setNames(names);
// AF entry (Array) in catalog with the FileSpec
COSBase AFEntry = (COSBase) doc.getDocumentCatalog().getCOSObject().getItem("AF");
COSBase AFEntry = doc.getDocumentCatalog().getCOSObject().getItem("AF");
if ((AFEntry == null)) {
COSArray cosArray = new COSArray();
cosArray.add(fs);
@@ -529,7 +556,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
metadata.addSchema(pdfaex);
}
private void removeCidSet(PDDocumentCatalog catalog, PDDocument doc)
private void removeCidSet(PDDocument doc)
throws IOException
{
// https://github.com/ZUGFeRD/mustangproject/issues/249
@@ -550,7 +577,8 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
PDType0Font typedFont = (PDType0Font) pdFont;
if (typedFont.getDescendantFont() instanceof PDCIDFontType2) {
PDCIDFontType2 f = (PDCIDFontType2) typedFont.getDescendantFont();
@SuppressWarnings ("unused")
PDCIDFontType2 f = (PDCIDFontType2) typedFont.getDescendantFont();
PDFontDescriptor fontDescriptor = pdFont.getFontDescriptor();
fontDescriptor.getCOSObject().removeItem(cidSet);
@@ -571,7 +599,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
metadata = new PDMetadata(doc);
cat.setMetadata(metadata);
removeCidSet(cat, doc);
removeCidSet(doc);
xmp = getXmpMetadata();
writeAdobePDFSchema(xmp);
writePDFAIdentificationSchema(xmp);
@@ -608,7 +636,8 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
* @throws IOException if anything is wrong with already loaded PDF
*/
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
@Override
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
this.trans = trans;
return prepare();
}
@@ -713,13 +742,13 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
}
protected PDFAIdentificationSchema getPDFAIdentificationSchema(XMPMetadata xmp) {
PDFAIdentificationSchema pdfaid = xmp.getPDFIdentificationSchema();
PDFAIdentificationSchema pdfaid = xmp.getPDFAIdentificationSchema();
if (pdfaid != null)
if (overwrite)
xmp.removeSchema(pdfaid);
else
return pdfaid;
return xmp.createAndAddPFAIdentificationSchema();
return xmp.createAndAddPDFAIdentificationSchema();
}
protected void writeDublinCoreSchema(XMPMetadata xmp) {
@@ -760,7 +789,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
if (overwrite || isEmpty(xsb.getCreatorTool()) || "UnknownApplication".equals(xsb.getCreatorTool()))
xsb.setCreatorTool(creatorTool);
if (overwrite || xsb.getCreateDate() == null)
xsb.setCreateDate(GregorianCalendar.getInstance());
xsb.setCreateDate(Calendar.getInstance());
}
protected XMPBasicSchema getXmpBasicSchema(XMPMetadata xmp) {

View File

@@ -20,6 +20,13 @@
*/
package org.mustangproject.ZUGFeRD;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
@@ -30,8 +37,7 @@ import org.apache.xmpbox.xml.XmpParsingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.activation.DataSource;
import java.io.*;
import jakarta.activation.DataSource;
/***
* Auto-detects the source PDF-A-Version and acts accordingly
@@ -43,14 +49,28 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
protected IZUGFeRDExporter theExporter;
protected boolean ignorePDFAErrors = false;
public ZUGFeRDExporterFromPDFA ignorePDFAErrors() {
this.ignorePDFAErrors = true;
return this;
}
protected void determineAndSetExporter(int PDFAVersion) {
if (PDFAVersion == 3) {
theExporter = new ZUGFeRDExporterFromA3();
if (ignorePDFAErrors) {
((ZUGFeRDExporterFromA3)theExporter).ignorePDFAErrors();
}
} else if (PDFAVersion == 1) {
theExporter = new ZUGFeRDExporterFromA1();
if (ignorePDFAErrors) {
((ZUGFeRDExporterFromA1)theExporter).ignorePDFAErrors();
}
} else {
throw new IllegalArgumentException("PDF-A version not supported");
}
}
protected IZUGFeRDExporter getExporter() {
if (theExporter==null) {
@@ -79,7 +99,7 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
* @throws IOException
*/
private int getPDFAVersion(byte[] byteArrayInputStream) throws IOException {
PDDocument document = PDDocument.load(byteArrayInputStream);
PDDocument document = Loader.loadPDF(byteArrayInputStream);
PDDocumentCatalog catalog = document.getDocumentCatalog();
PDMetadata metadata = catalog.getMetadata();
// the PDF version we could get through the document but we want the PDF-A version,
@@ -89,7 +109,7 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
DomXmpParser xmpParser = new DomXmpParser();
XMPMetadata xmp = xmpParser.parse(metadata.createInputStream());
PDFAIdentificationSchema pdfaSchema = xmp.getPDFIdentificationSchema();
PDFAIdentificationSchema pdfaSchema = xmp.getPDFAIdentificationSchema();
if (pdfaSchema != null) {
return pdfaSchema.getPart();
}
@@ -147,16 +167,16 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
return getExporter().setCreator(creator);
}
public ZUGFeRDExporterFromPDFA setProfile(Profile p) {
return (ZUGFeRDExporterFromPDFA) getExporter().setProfile(p);
public IZUGFeRDExporter setProfile(Profile p) {
return getExporter().setProfile(p);
}
public ZUGFeRDExporterFromPDFA setProfile(String profileName) {
public IZUGFeRDExporter setProfile(String profileName) {
Profile p = Profiles.getByName(profileName);
if (p==null) {
throw new RuntimeException("Profile not found.");
}
return (ZUGFeRDExporterFromPDFA) getExporter().setProfile(p);
return getExporter().setProfile(p);
}
public IZUGFeRDExporter setConformanceLevel(PDFAConformanceLevel newLevel) {

View File

@@ -14,22 +14,19 @@ package org.mustangproject.ZUGFeRD;
* @author jstaerk
*/
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -40,6 +37,8 @@ import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
@@ -49,12 +48,16 @@ import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
import org.mustangproject.EStandard;
import org.mustangproject.Item;
import org.mustangproject.Product;
import org.mustangproject.XMLTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class ZUGFeRDImporter {
private static final Logger LOGGER = LoggerFactory.getLogger (ZUGFeRDImporter.class);
/**
* if metadata has been found
@@ -80,14 +83,14 @@ public class ZUGFeRDImporter {
protected ZUGFeRDImporter() {
//constructor for extending classes
//constructor for extending classes
}
public ZUGFeRDImporter(String pdfFilename) {
try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) {
extractLowLevel(bis);
} catch (final IOException e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
LOGGER.error ("Failed to extract ZUGFeRD data", e);
throw new ZUGFeRDExportException(e);
}
}
@@ -97,7 +100,7 @@ public class ZUGFeRDImporter {
try {
extractLowLevel(pdfStream);
} catch (final IOException e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
LOGGER.error ("Failed to extract ZUGFeRD data", e);
throw new ZUGFeRDExportException(e);
}
}
@@ -106,41 +109,59 @@ public class ZUGFeRDImporter {
/**
* Extracts a ZUGFeRD invoice from a PDF document represented by an input stream. Errors are reported via exception handling.
*
* @param pdfStream a inputstream of a pdf file
* @param inStream a inputstream of a pdf file
*/
private void extractLowLevel(InputStream pdfStream) throws IOException {
try (PDDocument doc = PDDocument.load(pdfStream)) {
// PDDocumentInformation info = doc.getDocumentInformation();
final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
//start
private void extractLowLevel(InputStream inStream) throws IOException {
BufferedInputStream pdfStream = new BufferedInputStream(inStream);
byte[] pad = new byte[4];
pdfStream.mark(0);
pdfStream.read(pad);
pdfStream.reset();
byte[] pdfSignature = {'%', 'P', 'D', 'F'};
if (Arrays.equals(pad, pdfSignature)) { // we have a pdf
if (doc.getDocumentCatalog() == null || doc.getDocumentCatalog().getMetadata() == null) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.INFO, "no-xmlpart");
return;
}
final InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata();
xmpString = convertStreamToString(XMP);
try (PDDocument doc = Loader.loadPDF(IOUtils.toByteArray (pdfStream))) {
// PDDocumentInformation info = doc.getDocumentInformation();
final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
//start
final PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles();
if (etn == null) {
return;
}
if (doc.getDocumentCatalog() == null || doc.getDocumentCatalog().getMetadata() == null) {
LOGGER.info("no-xmlpart");
return;
}
final Map<String, PDComplexFileSpecification> efMap = etn.getNames();
// String filePath = "/tmp/";
final InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata();
xmpString = convertStreamToString(XMP);
if (efMap != null) {
extractFiles(efMap); // see
// https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/
} else {
final PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles();
if (etn == null) {
return;
}
final List<PDNameTreeNode<PDComplexFileSpecification>> kids = etn.getKids();
for (final PDNameTreeNode<PDComplexFileSpecification> node : kids) {
final Map<String, PDComplexFileSpecification> namesL = node.getNames();
extractFiles(namesL);
final Map<String, PDComplexFileSpecification> efMap = etn.getNames();
// String filePath = "/tmp/";
if (efMap != null) {
extractFiles(efMap); // see
// https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/
} else {
final List<PDNameTreeNode<PDComplexFileSpecification>> kids = etn.getKids();
if (kids == null) {
return;
}
for (final PDNameTreeNode<PDComplexFileSpecification> node : kids) {
final Map<String, PDComplexFileSpecification> namesL = node.getNames();
extractFiles(namesL);
}
}
}
} else {
// no PDF probably XML
containsMeta = true;
setRawXML(XMLTools.getBytesFromStream(pdfStream));
}
}
@@ -187,7 +208,7 @@ public class ZUGFeRDImporter {
xmlFact.setNamespaceAware(true);
final DocumentBuilder builder = xmlFact.newDocumentBuilder();
final ByteArrayInputStream is = new ByteArrayInputStream(rawXML);
/// is.skip(guessBOMSize(is));
/// is.skip(guessBOMSize(is));
document = builder.parse(is);
}
@@ -198,14 +219,12 @@ public class ZUGFeRDImporter {
try {
setDocument();
} catch (ParserConfigurationException | SAXException e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
LOGGER.error ("Failed to parse XML", e);
throw new ZUGFeRDExportException(e);
}
}
protected String extractString(String xpathStr) {
if (!containsMeta) {
throw new ZUGFeRDExportException("No suitable data/ZUGFeRD file could be found.");
@@ -217,7 +236,7 @@ public class ZUGFeRDImporter {
final XPath xpath = xpathFact.newXPath();
result = xpath.evaluate(xpathStr, document);
} catch (final XPathExpressionException e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
LOGGER.error ("Failed to evaluate XPath", e);
throw new ZUGFeRDExportException(e);
}
return result;
@@ -248,7 +267,11 @@ public class ZUGFeRDImporter {
* @return the ZUGFeRD Profile
*/
public String getZUGFeRDProfil() {
switch (extractString("//*[local-name() = 'GuidelineSpecifiedDocumentContextParameter']//*[local-name() = 'ID']")) {
String guideline = extractString("//*[local-name() = 'GuidelineSpecifiedDocumentContextParameter']//*[local-name() = 'ID']");
if(guideline.contains("xrechnung")) {
return "XRECHNUNG";
}
switch (guideline) {
case "urn:cen.eu:en16931:2017":
case "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort":
return "COMFORT";
@@ -262,9 +285,9 @@ public class ZUGFeRDImporter {
case "urn:ferd:CrossIndustryDocument:invoice:1p0:extended":
case "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended":
return "EXTENDED";
default:
return "";
}
default:
return "";
}
}
/**
@@ -278,8 +301,7 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'ApplicableHeaderTradeSettlement']//*[local-name() = 'InvoiceCurrencyCode']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
@@ -298,7 +320,7 @@ public class ZUGFeRDImporter {
return extractIssuerAssignedID("SellerOrderReferencedDocument");
}
/**
/**
* @return the IssuerAssigned ID
*/
public String getContractOrderReferencedDocumentIssuerAssignedID() {
@@ -313,7 +335,7 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = '" + propertyName + "']//*[local-name() = 'IssuerAssignedID']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
@@ -336,25 +358,26 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'ExchangedDocument']//*[local-name() = 'IssueDateTime']//*[local-name() = 'DateTimeString']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
public Date getDetailedDeliveryPeriodFrom(){
final String toParse = extractString(
"//*[local-name() = 'ApplicableHeaderTradeSettlement']" +
"//*[local-name() = 'BillingSpecifiedPeriod']" +
"//*[local-name() = 'StartDateTime']//*[local-name() = 'DateTimeString']");
return tryDate(toParse);
}
public Date getDetailedDeliveryPeriodTo(){
final String toParse = extractString(
"//*[local-name() = 'ApplicableHeaderTradeSettlement']" +
"//*[local-name() = 'BillingSpecifiedPeriod']" +
"//*[local-name() = 'EndDateTime']//*[local-name() = 'DateTimeString']");
return tryDate(toParse);
}
public Date getDetailedDeliveryPeriodFrom() {
final String toParse = extractString(
"//*[local-name() = 'ApplicableHeaderTradeSettlement']" +
"//*[local-name() = 'BillingSpecifiedPeriod']" +
"//*[local-name() = 'StartDateTime']//*[local-name() = 'DateTimeString']");
return tryDate(toParse);
}
public Date getDetailedDeliveryPeriodTo() {
final String toParse = extractString(
"//*[local-name() = 'ApplicableHeaderTradeSettlement']" +
"//*[local-name() = 'BillingSpecifiedPeriod']" +
"//*[local-name() = 'EndDateTime']//*[local-name() = 'DateTimeString']");
return tryDate(toParse);
}
/**
* @return the TaxBasisTotalAmount
@@ -367,7 +390,7 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']//*[local-name() = 'TaxBasisTotalAmount']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
@@ -383,7 +406,7 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']//*[local-name() = 'TaxTotalAmount']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
@@ -399,7 +422,7 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']//*[local-name() = 'RoundingAmount']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
@@ -415,7 +438,7 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']//*[local-name() = 'TotalPrepaidAmount']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
@@ -453,7 +476,7 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'ExchangedDocument']//*[local-name() = 'IncludedNote']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
@@ -463,7 +486,9 @@ public class ZUGFeRDImporter {
*/
public String getBuyerTradePartyName() {
return extractString("//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'Name']");
} /**
}
/**
* @return the BuyerTradeParty Name
*/
public String getDeliveryTradePartyName() {
@@ -471,7 +496,6 @@ public class ZUGFeRDImporter {
}
/**
* @return the line Total Amount
*/
@@ -483,7 +507,7 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']//*[local-name() = 'LineTotalAmount']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
@@ -506,7 +530,7 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'ActualDeliverySupplyChainEvent']//*[local-name() = 'OccurrenceDateTime']//*[local-name() = 'DateTimeString']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
@@ -522,13 +546,12 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'ExchangedDocument']//*[local-name() = 'ID']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
/**
* @return the document code
*/
@@ -540,7 +563,7 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'ExchangedDocument']/*[local-name() = 'TypeCode']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
@@ -557,7 +580,7 @@ public class ZUGFeRDImporter {
return extractString("//*[local-name() = 'ApplicableHeaderTradeAgreement']/*[local-name() = 'BuyerReference']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return "";
}
}
@@ -600,7 +623,7 @@ public class ZUGFeRDImporter {
if (result == null || result.isEmpty()) {
/* fx/zf would be SpecifiedTradeSettlementMonetarySummation
* but ox is SpecifiedTradeSettlementHeaderMonetarySummation...*/
* but ox is SpecifiedTradeSettlementHeaderMonetarySummation...*/
result = extractString("//*[local-name() = 'GrandTotalAmount']");
}
return result;
@@ -664,7 +687,7 @@ public class ZUGFeRDImporter {
throw new Exception("Not yet parsed");
}
final String head = getUTF8();
String rootNode=extractString("local-name(/*)");
String rootNode = extractString("local-name(/*)");
if (rootNode.equals("CrossIndustryDocument")) {
return EStandard.zugferd;
} else if (rootNode.equals("Invoice")) {
@@ -680,26 +703,26 @@ public class ZUGFeRDImporter {
throw new Exception("ZUGFeRD version could not be determined");
}
public int getVersion() throws Exception {
if (!containsMeta) {
throw new Exception("Not yet parsed");
}
if (version != null) {
return version;
}
return version;
}
final String head = getUTF8();
if (head.contains("<rsm:CrossIndustryDocument") //
|| head.contains("<CrossIndustryDocument") //
|| head.contains("<SCRDMCCBDACIDAMessageStructure") //
|| head.contains("<rsm:SCRDMCCBDACIOMessageStructure")) { //
|| head.contains("<CrossIndustryDocument") //
|| head.contains("<SCRDMCCBDACIDAMessageStructure") //
|| head.contains("<rsm:SCRDMCCBDACIOMessageStructure")) { //
version = 1;
} else if (head.contains("<rsm:CrossIndustryInvoice")) {
version = 2;
} else {
throw new Exception("ZUGFeRD version could not be determined");
}
else {
throw new Exception("ZUGFeRD version could not be determined");
}
return version;
}
@@ -719,12 +742,12 @@ public class ZUGFeRDImporter {
final byte[] bomlessData;
if ((rawXML[0] == (byte) 0xEF)
&& (rawXML[1] == (byte) 0xBB)
&& (rawXML[2] == (byte) 0xBF)) {
&& (rawXML[1] == (byte) 0xBB)
&& (rawXML[2] == (byte) 0xBF)) {
// I don't like BOMs, lets remove it
bomlessData = new byte[rawXML.length - 3];
System.arraycopy(rawXML, 3, bomlessData, 0,
rawXML.length - 3);
rawXML.length - 3);
} else {
bomlessData = rawXML;
}
@@ -754,19 +777,21 @@ public class ZUGFeRDImporter {
// indication if zugferd is present - better than just invoice
final String meta = getMeta();
return (meta != null) && (meta.length() > 0) && ((meta.contains("SpecifiedExchangedDocumentContext")
/* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */));
/* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */));
}
static String convertStreamToString(java.io.InputStream is) {
// source https://stackoverflow.com/questions/309424/how-do-i-read-convert-an-inputstream-into-a-string-in-java referring to
// https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks
final Scanner s = new Scanner(is, "UTF-8").useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
try {
return IOUtils.toString(is, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* returns an instance of PostalTradeAddress for SellerTradeParty section
*
* @return an instance of PostalTradeAddress
*/
public PostalTradeAddress getBuyerTradePartyAddress() {
@@ -780,7 +805,7 @@ public class ZUGFeRDImporter {
nl = getNodeListByPath("//*[local-name() = 'CrossIndustryInvoice']//*[local-name() = 'SupplyChainTradeTransaction']//*[local-name() = 'ApplicableHeaderTradeAgreement']//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'PostalTradeAddress']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return null;
}
@@ -789,6 +814,7 @@ public class ZUGFeRDImporter {
/**
* returns an instance of PostalTradeAddress for SellerTradeParty section
*
* @return an instance of PostalTradeAddress
*/
public PostalTradeAddress getSellerTradePartyAddress() {
@@ -801,15 +827,16 @@ public class ZUGFeRDImporter {
nl = getNodeListByPath("//*[local-name() = 'CrossIndustryInvoice']//*[local-name() = 'SupplyChainTradeTransaction']//*[local-name() = 'ApplicableHeaderTradeAgreement']//*[local-name() = 'SellerTradeParty']//*[local-name() = 'PostalTradeAddress']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return null;
}
return getAddressFromNodeList(nl);
}
/**
}
/**
* returns an instance of PostalTradeAddress for ShipToTradeParty section
*
* @return an instance of PostalTradeAddress
*/
public PostalTradeAddress getDeliveryTradePartyAddress() {
@@ -822,7 +849,7 @@ public class ZUGFeRDImporter {
nl = getNodeListByPath("//*[local-name() = 'CrossIndustryInvoice']//*[local-name() = 'SupplyChainTradeTransaction']//*[local-name() = 'ApplicableHeaderTradeDelivery']//*[local-name() = 'ShipToTradeParty']//*[local-name() = 'PostalTradeAddress']");
}
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
return null;
}
@@ -839,7 +866,7 @@ public class ZUGFeRDImporter {
for (int j = 0; j < nodes.getLength(); j++) {
n = nodes.item(j);
final short nodeType = n.getNodeType();
if ((nodeType==Node.ELEMENT_NODE)&&(n.getLocalName()!=null)){
if ((nodeType == Node.ELEMENT_NODE) && (n.getLocalName() != null)) {
switch (n.getLocalName()) {
case "PostcodeCode":
address.setPostCodeCode("");
@@ -893,21 +920,22 @@ public class ZUGFeRDImporter {
/**
* returns a list of LineItems
*
* @return a List of LineItem instances
*/
public List<Item> getLineItemList() {
final List<Node> nodeList = getLineItemNodes();
final List<Item> lineItemList = new ArrayList<>();
for (final Node n: nodeList) {
for (final Node n : nodeList) {
final Item lineItem = new Item(null, null, null);
lineItem.setProduct(new Product(null,null,null,null));
lineItem.setProduct(new Product(null, null, null, null));
final NodeList nl = n.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
final Node nn = nl.item(i);
Node node = null;
if (nn.getLocalName()!=null) {
if (nn.getLocalName() != null) {
switch (nn.getLocalName()) {
case "SpecifiedLineTradeAgreement":
case "SpecifiedSupplyChainTradeAgreement":
@@ -975,17 +1003,17 @@ public class ZUGFeRDImporter {
node = getNodeByName(nn.getChildNodes(), "BillingSpecifiedPeriod");
if (node != null) {
final Node start = getNodeByName(node.getChildNodes(), "StartDateTime");
Node dateTimeStart = null;
if(start != null) {
dateTimeStart = getNodeByName(start.getChildNodes(), "DateTimeString");
}
final Node end = getNodeByName(node.getChildNodes(), "EndDateTime");
Node dateTimeEnd = null;
if(end != null) {
dateTimeEnd = getNodeByName(end.getChildNodes(), "DateTimeString");
}
lineItem.setDetailedDeliveryPeriod(tryDate(dateTimeStart), tryDate(dateTimeEnd));
}
Node dateTimeStart = null;
if (start != null) {
dateTimeStart = getNodeByName(start.getChildNodes(), "DateTimeString");
}
final Node end = getNodeByName(node.getChildNodes(), "EndDateTime");
Node dateTimeEnd = null;
if (end != null) {
dateTimeEnd = getNodeByName(end.getChildNodes(), "DateTimeString");
}
lineItem.setDetailedDeliveryPeriod(tryDate(dateTimeStart), tryDate(dateTimeEnd));
}
node = getNodeByName(nn.getChildNodes(), "SpecifiedTradeSettlementLineMonetarySummation");
if (node != null) {
@@ -1024,16 +1052,17 @@ public class ZUGFeRDImporter {
/**
* returns a List of LineItem Nodes from ZUGFeRD XML
*
* @return a List of Node instances
*/
public List<Node> getLineItemNodes() {
final List<Node> lineItemNodes = new ArrayList<>();
NodeList nl = null;
try {
nl = getNodeListByPath("//*[local-name() = 'IncludedSupplyChainTradeLineItem']");
nl = getNodeListByPath("//*[local-name() = 'IncludedSupplyChainTradeLineItem']");
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
// Exception was already logged
}
for (int i = 0; i < nl.getLength(); i++) {
@@ -1045,13 +1074,14 @@ public class ZUGFeRDImporter {
/**
* Returns a node, found by name. If more nodes with the same name are present, the first occurence will be returned
* @param nl - A NodeList which may contains the searched node
*
* @param nl - A NodeList which may contains the searched node
* @param name The nodes name
* @return a Node or null, if nothing is found
*/
private Node getNodeByName(NodeList nl, String name) {
for (int i = 0; i < nl.getLength(); i++) {
if ((nl.item(i).getLocalName()!=null)&&(nl.item(i).getLocalName().equals(name))) {
if ((nl.item(i).getLocalName() != null) && (nl.item(i).getLocalName().equals(name))) {
return nl.item(i);
} else if (nl.item(i).getChildNodes().getLength() > 0) {
final Node node = getNodeByName(nl.item(i).getChildNodes(), name);
@@ -1065,6 +1095,7 @@ public class ZUGFeRDImporter {
/**
* Get a NodeList by providing an path
*
* @param path a compliable Path
* @return a Nodelist or null, if an error occurs
*/
@@ -1078,25 +1109,27 @@ public class ZUGFeRDImporter {
final XPathExpression xpr = xPath.compile(s);
return (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
} catch (final Exception e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
LOGGER.error("Failed to evaluate XPath", e);
return null;
}
}
/**
* returns the value of an node
*
* @param node the Node to get the value from
* @return A String or empty String, if no value was found
*/
private String getNodeValue(Node node) {
if (node != null && node.getFirstChild() != null) {
return node.getFirstChild().getNodeValue();
}
if (node != null && node.getFirstChild() != null) {
return node.getFirstChild().getNodeValue();
}
return "";
}
/**
* tries to convert an String to BigDecimal.
*
* @param nodeValue The value as String
* @return a BigDecimal with the value provides as String or a BigDecimal with value 0.00 if an error occurs
*/
@@ -1111,20 +1144,21 @@ public class ZUGFeRDImporter {
}
}
}
private Date tryDate(Node node) {
final String nodeValue = getNodeValue(node);
if (nodeValue.isEmpty()) {
return null;
}
return tryDate(nodeValue);
}
private static Date tryDate(String toParse) {
final SimpleDateFormat formatter = ZUGFeRDDateFormat.DATE.getFormatter();
try {
return formatter.parse(toParse);
} catch (final Exception e) {
return null;
private Date tryDate(Node node) {
final String nodeValue = getNodeValue(node);
if (nodeValue.isEmpty()) {
return null;
}
}
return tryDate(nodeValue);
}
private static Date tryDate(String toParse) {
final SimpleDateFormat formatter = ZUGFeRDDateFormat.DATE.getFormatter();
try {
return formatter.parse(toParse);
} catch (final Exception e) {
return null;
}
}
}

View File

@@ -3,12 +3,12 @@ package org.mustangproject.ZUGFeRD;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
@@ -17,13 +17,11 @@ import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.mustangproject.Allowance;
import org.mustangproject.BankDetails;
import org.mustangproject.Charge;
import org.mustangproject.EStandard;
import org.mustangproject.Invoice;
import org.mustangproject.Item;
import org.mustangproject.Product;
import org.mustangproject.ReferencedDocument;
import org.mustangproject.SchemedID;
import org.mustangproject.TradeParty;
import org.mustangproject.XMLTools;
import org.slf4j.Logger;
@@ -75,10 +73,10 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
*/
XPathFactory xpathFact = XPathFactory.newInstance();
XPath xpath = xpathFact.newXPath();
XPathExpression xpr = xpath.compile("//*[local-name()=\"SellerTradeParty\"]|//*[local-name()=\"AccountingSupplierParty\"]");
XPathExpression xpr = xpath.compile("//*[local-name()=\"SellerTradeParty\"]|//*[local-name()=\"AccountingSupplierParty\"]/*");
NodeList SellerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
xpr = xpath.compile("//*[local-name()=\"BuyerTradeParty\"]|//*[local-name()=\"AccountingCustomerParty\"]");
xpr = xpath.compile("//*[local-name()=\"BuyerTradeParty\"]|//*[local-name()=\"AccountingCustomerParty\"]/*");
NodeList BuyerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
xpr = xpath.compile("//*[local-name()=\"ExchangedDocument\"]|//*[local-name()=\"HeaderExchangedDocument\"]");
NodeList ExchangedDocumentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
@@ -118,17 +116,22 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
}
}
}
String rootNode=extractString("local-name(/*)");
if (rootNode.equals("Invoice"))
{
// UBL...
String rootNode = extractString("local-name(/*)");
if (rootNode.equals("Invoice")) {
// UBL...
number = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"ID\"]").trim();
issueDate=new SimpleDateFormat("yyyy-MM-dd")
issueDate = new SimpleDateFormat("yyyy-MM-dd")
.parse(extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"IssueDate\"]").trim());
dueDate=new SimpleDateFormat("yyyy-MM-dd")
.parse(extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"DueDate\"]").trim());
deliveryDate=new SimpleDateFormat("yyyy-MM-dd")
.parse(extractString("//*[local-name()=\"Delivery\"]/*[local-name()=\"ActualDeliveryDate\"]").trim());
String dueDt = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"DueDate\"]").trim();
if (dueDt.length() > 0) {
dueDate = new SimpleDateFormat("yyyy-MM-dd")
.parse(dueDt);
}
String deliveryDt = extractString("//*[local-name()=\"Delivery\"]/*[local-name()=\"ActualDeliveryDate\"]").trim();
if (deliveryDt.length() > 0) {
deliveryDate = new SimpleDateFormat("yyyy-MM-dd")
.parse(deliveryDt);
}
}
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeDelivery\"]");
NodeList headerTradeDeliveryNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
@@ -208,6 +211,7 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]|//*[local-name()=\"ApplicableSupplyChainTradeSettlement\"]");
NodeList headerTradeSettlementNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
List<BankDetails> bankDetails = new ArrayList<>();
for (int i = 0; i < headerTradeSettlementNodes.getLength(); i++) {
// nodes.item(i).getTextContent())) {
@@ -235,11 +239,81 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
}
}
}
if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
&& (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName()
.equals("SpecifiedTradeSettlementPaymentMeans"))) {
NodeList paymentMeansChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes();
for (int paymentMeansChildIndex = 0; paymentMeansChildIndex < paymentMeansChilds
.getLength(); paymentMeansChildIndex++) {
String IBAN = null, BIC = null;
if ((paymentMeansChilds.item(paymentMeansChildIndex).getLocalName() != null) && (paymentMeansChilds
.item(paymentMeansChildIndex).getLocalName().equals("PayeePartyCreditorFinancialAccount"))) {
NodeList accountChilds = paymentMeansChilds.item(paymentMeansChildIndex).getChildNodes();
for (int accountChildIndex = 0; accountChildIndex < accountChilds
.getLength(); accountChildIndex++) {
if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds
.item(accountChildIndex).getLocalName().equals("IBANID"))) {//CII
IBAN = accountChilds.item(accountChildIndex).getTextContent();
}
}
}
if ((paymentMeansChilds.item(paymentMeansChildIndex).getLocalName() != null) && (paymentMeansChilds
.item(paymentMeansChildIndex).getLocalName().equals("PayeePartyCreditorFinancialInstitution"))) {
NodeList accountChilds = paymentMeansChilds.item(paymentMeansChildIndex).getChildNodes();
for (int accountChildIndex = 0; accountChildIndex < accountChilds
.getLength(); accountChildIndex++) {
if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds
.item(accountChildIndex).getLocalName().equals("BICID"))) {//CII
BIC = accountChilds.item(accountChildIndex).getTextContent();
}
}
}
if (IBAN != null) {
BankDetails bd = new BankDetails(IBAN);
if (BIC != null) {
bd.setBIC(BIC);
}
bankDetails.add(bd);
}
}
}
}
}
xpr = xpath.compile("//*[local-name()=\"PaymentMeans\"]"); //UBL only
NodeList paymentMeansNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < paymentMeansNodes.getLength(); i++) {
// nodes.item(i).getTextContent())) {
Node paymentMeansNode = paymentMeansNodes.item(i);
NodeList paymentMeansChilds = paymentMeansNode.getChildNodes();
for (int meansChildIndex = 0; meansChildIndex < paymentMeansChilds
.getLength(); meansChildIndex++) {
if ((paymentMeansChilds.item(meansChildIndex).getLocalName() != null)
&& (paymentMeansChilds.item(meansChildIndex).getLocalName()
.equals("PayeeFinancialAccount"))) {
NodeList paymentTermChilds = paymentMeansChilds.item(meansChildIndex).getChildNodes();
for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds
.getLength(); paymentTermChildIndex++) {
if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds
.item(paymentTermChildIndex).getLocalName().equals("ID"))) {
String IBAN = paymentTermChilds.item(paymentTermChildIndex).getTextContent();
if (IBAN != null) {
BankDetails bd = new BankDetails(IBAN);
bankDetails.add(bd);
}
}
}
}
}
}
zpp.setDueDate(dueDate).setDeliveryDate(deliveryDate).setIssueDate(issueDate)
.setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number);
bankDetails.forEach(bankDetail -> zpp.getSender().addBankDetails(bankDetail));
if (buyerOrderIssuerAssignedID != null) {
zpp.setBuyerOrderReferencedDocumentID(buyerOrderIssuerAssignedID);
}
@@ -263,8 +337,7 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
xpr = xpath.compile("//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]|//*[local-name()=\"InvoiceLine\"]");
NodeList nodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (nodes.getLength() == 0) {
} else {
if (nodes.getLength() != 0) {
for (int i = 0; i < nodes.getLength(); i++) {
Node currentItemNode = nodes.item(i);

View File

@@ -20,28 +20,56 @@
*/
package org.mustangproject.ZUGFeRD;
import org.apache.fop.apps.*;
import org.apache.fop.configuration.Configuration;
import org.apache.fop.configuration.ConfigurationException;
import org.apache.fop.configuration.DefaultConfigurationBuilder;
import org.apache.xmlgraphics.util.MimeConstants;
import org.mustangproject.CII.CIIToUBL;
import org.mustangproject.ClasspathResolverURIAdapter;
import org.xml.sax.SAXException;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.xml.transform.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.FopFactoryBuilder;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.fop.configuration.Configuration;
import org.apache.fop.configuration.ConfigurationException;
import org.apache.fop.configuration.DefaultConfigurationBuilder;
import org.apache.xmlgraphics.util.MimeConstants;
import org.mustangproject.ClasspathResolverURIAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.helger.commons.io.stream.StreamHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class ZUGFeRDVisualizer {
@@ -53,7 +81,7 @@ public class ZUGFeRDVisualizer {
static final ClassLoader CLASS_LOADER = ZUGFeRDVisualizer.class.getClassLoader();
private static final String RESOURCE_PATH = "";
private static final Logger LOG = Logger.getLogger(ZUGFeRDVisualizer.class.getName());
private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRDVisualizer.class);
// private static File createTempFileResult(final Transformer transformer, final
// StreamSource toTransform,
// final String suffix) throws TransformerException, IOException {
@@ -79,27 +107,27 @@ public class ZUGFeRDVisualizer {
}
public String visualize(String xmlFilename, Language lang)
throws FileNotFoundException, TransformerException, UnsupportedEncodingException {
throws FileNotFoundException, TransformerException, IOException, SAXException, ParserConfigurationException {
try {
if (mXsltXRTemplate == null) {
mXsltXRTemplate = mFactory.newTemplates(
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
}
if (mXsltPDFTemplate == null) {
mXsltPDFTemplate = mFactory.newTemplates(
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl")));
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl")));
}
if (mXsltHTMLTemplate == null) {
mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource(
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html." + lang.name().toLowerCase() + ".xsl")));
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html." + lang.name().toLowerCase() + ".xsl")));
}
if (mXsltZF1HTMLTemplate == null) {
mXsltZF1HTMLTemplate = mFactory.newTemplates(new StreamSource(
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt")));
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt")));
}
} catch (TransformerConfigurationException ex) {
LOG.log(Level.SEVERE, null, ex);
LOGGER.error("Failed to init XSLT templates", ex);
}
/**
@@ -113,35 +141,40 @@ public class ZUGFeRDVisualizer {
try {
fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename)), StandardCharsets.UTF_8);
} catch (IOException e2) {
LOG.log(Level.SEVERE, null, e2);
LOGGER.error("Failed to read file content", e2);
}
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String zf1Signature = "rsm:CrossIndustryDocument";
String zf2Signature = "rsm:CrossIndustryInvoice";
String ublSignature = "ubl:Invoice";
String ublCreditNoteSignature = "ubl:CreditNote";
String zf1Signature = "CrossIndustryDocument";
String zf2Signature = "CrossIndustryInvoice";
String ublSignature = "Invoice";
String ublCreditNoteSignature = "CreditNote";
boolean doPostProcessing = false;
if (fileContent.contains(zf1Signature)) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(fis));
Element root = doc.getDocumentElement();
fis = new FileInputStream(xmlFilename); // fis wont reset() so re-read from beginning
if (root.getLocalName().equals(zf1Signature)) {
applyZF1XSLT(fis, baos);
} else if (fileContent.contains(zf2Signature)) {
} else if (root.getLocalName().equals(zf2Signature)) {
//zf2 or fx
applyZF2XSLT(fis, iaos);
doPostProcessing = true;
} else if (fileContent.contains(ublSignature)) {
} else if (root.getLocalName().equals(ublSignature)) {
//zf2 or fx
applyUBL2XSLT(fis, iaos);
doPostProcessing = true;
} else if (fileContent.contains(ublCreditNoteSignature)) {
} else if (root.getLocalName().equals(ublCreditNoteSignature)) {
//zf2 or fx
applyUBLCreditNote2XSLT(fis, iaos);
doPostProcessing = true;
} else {
throw new IllegalArgumentException("File does not look like CII or UBL");
}
if (doPostProcessing) {
// take the copy of the stream and re-write it to an InputStream
@@ -158,54 +191,46 @@ public class ZUGFeRDVisualizer {
// ByteArrayOutputStream
iaos.writeTo(out);
} catch (IOException e) {
LOG.log(Level.SEVERE, null, e);
LOGGER.error("Failed to write to stream", e);
} finally {
// close the PipedOutputStream here because we're done writing data
// once this thread has completed its run
if (out != null) {
// close the PipedOutputStream cleanly
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
LOG.log(Level.SEVERE, null, e);
}
}
StreamHelper.close(out);
}
}
}).start();
applyXSLTToHTML(in, baos);
} catch (IOException e1) {
LOG.log(Level.SEVERE, null, e1);
LOGGER.error("Failed to create HTML", e1);
}
}
return baos.toString("UTF-8");
return baos.toString(StandardCharsets.UTF_8);
}
protected String toFOP(String xmlFilename)
throws FileNotFoundException, TransformerException, UnsupportedEncodingException {
throws FileNotFoundException, TransformerException {
try {
if (mXsltXRTemplate == null) {
mXsltXRTemplate = mFactory.newTemplates(
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
}
if (mXsltPDFTemplate == null) {
mXsltPDFTemplate = mFactory.newTemplates(
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl")));
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl")));
}
} catch (TransformerConfigurationException ex) {
LOG.log(Level.SEVERE, null, ex);
LOGGER.error("Failed to init XSLT templates", ex);
}
FileInputStream fis = new FileInputStream(xmlFilename);
String fileContent = "";
try {
fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename)), StandardCharsets.UTF_8);
// TODO why are we reading the whole file here and discarding the content?
new String(Files.readAllBytes(Paths.get(xmlFilename)), StandardCharsets.UTF_8);
} catch (IOException e2) {
LOG.log(Level.SEVERE, null, e2);
LOGGER.error("Failed to read file", e2);
}
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
@@ -227,39 +252,28 @@ public class ZUGFeRDVisualizer {
// ByteArrayOutputStream
iaos.writeTo(out);
} catch (IOException e) {
LOG.log(Level.SEVERE, null, e);
LOGGER.error("Failed to write to stream", e);
} finally {
// close the PipedOutputStream here because we're done writing data
// once this thread has completed its run
if (out != null) {
// close the PipedOutputStream cleanly
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
LOG.log(Level.SEVERE, null, e);
}
}
StreamHelper.close(out);
}
}
}).start();
applyXSLTToPDF(in, baos);
} catch (IOException e1) {
LOG.log(Level.SEVERE, null, e1);
LOGGER.error("Failed to create PDF", e1);
}
return baos.toString("UTF-8");
return baos.toString(StandardCharsets.UTF_8);
}
public void toPDF(String xmlFilename, String pdfFilename) {
// the writing part
CIIToUBL c2u = new CIIToUBL();
String sourceFilename = "factur-x.xml";
File CIIinputFile = new File(xmlFilename);
String expected = null;
String result = null;
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
@@ -268,12 +282,8 @@ public class ZUGFeRDVisualizer {
*/
try {
result = zvi.toFOP(CIIinputFile.getAbsolutePath());
} catch (FileNotFoundException e) {
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
} catch (TransformerException e) {
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
} catch (UnsupportedEncodingException e) {
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
} catch (FileNotFoundException | TransformerException e) {
LOGGER.error("Failed to apply FOP", e);
}
/*
FopConfParser parser = null;
@@ -304,6 +314,11 @@ public class ZUGFeRDVisualizer {
FopFactory fopFactory = builder.build();//FopFactory.newInstance(new File("c:\\Users\\jstaerk\\temp\\fop-config.xconf"));
fopFactory.getFontManager().setResourceResolver(
ResourceResolverFactory.createInternalResourceResolver(
new File(".").toURI(),
new ClasspathResolverURIAdapter()));
FOUserAgent userAgent = fopFactory.newFOUserAgent();
userAgent.getRendererOptions().put("pdf-a-mode", "PDF/A-1b");
@@ -332,31 +347,23 @@ public class ZUGFeRDVisualizer {
//Files.write(Paths.get("C:\\Users\\jstaerk\\temp\\fop.pdf"), res.toString().getBytes(StandardCharsets.UTF_8));
} catch (FOPException e) {
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
} catch (TransformerConfigurationException e) {
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
} catch (IOException e) {
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
} catch (TransformerException e) {
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
} catch (FOPException | IOException | TransformerException e) {
LOGGER.error("Failed to create PDF", e);
}
}
protected void applyZF2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
throws TransformerException {
throws TransformerException {
Transformer transformer = mXsltXRTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
}
protected void applyUBL2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
throws TransformerException {
throws TransformerException {
if (mXsltUBLTemplate == null) {
mXsltUBLTemplate = mFactory.newTemplates(
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ubl-invoice-xr.xsl")));
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ubl-invoice-xr.xsl")));
}
Transformer transformer = mXsltUBLTemplate.newTransformer();
@@ -364,10 +371,10 @@ public class ZUGFeRDVisualizer {
}
protected void applyUBLCreditNote2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
throws TransformerException {
throws TransformerException {
if (mXsltUBLTemplate == null) {
mXsltUBLTemplate = mFactory.newTemplates(
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ubl-creditnote-xr.xsl")));
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ubl-creditnote-xr.xsl")));
}
Transformer transformer = mXsltUBLTemplate.newTransformer();
@@ -375,21 +382,21 @@ public class ZUGFeRDVisualizer {
}
protected void applyZF1XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
throws TransformerException {
throws TransformerException {
Transformer transformer = mXsltZF1HTMLTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
}
protected void applyXSLTToHTML(final InputStream xmlFile, final OutputStream HTMLOutstream)
throws TransformerException {
throws TransformerException {
Transformer transformer = mXsltHTMLTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
}
protected void applyXSLTToPDF(final InputStream xmlFile, final OutputStream PDFOutstream)
throws TransformerException {
throws TransformerException {
Transformer transformer = mXsltPDFTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(PDFOutstream));

View File

@@ -25,7 +25,7 @@
<renderer mime="application/pdf">
<fonts><!-- https://xmlgraphics.apache.org/fop/1.1/fonts.html auto-embed -->
<auto-detect/>
<font kerning="no" embed-url="FreeSans.ttf" embedding-mode="subset">
<font kerning="no" embed-url="classpath:FreeSans.ttf" embedding-mode="subset">
<font-triplet name="SourceSerifPro" style="normal" weight="normal" />
<font-triplet name="Times-Bold" style="normal" weight="normal" />
</font>

View File

@@ -22,6 +22,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@@ -65,7 +66,7 @@ public class BackwardCompatibilityTest extends TestCase implements IExportableTr
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos);
ze.close();
String pdfContent = baos.toString("UTF-8");
String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
// check for pdf-a schema extension
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
@@ -105,7 +106,7 @@ public class BackwardCompatibilityTest extends TestCase implements IExportableTr
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos);
ze.close();
String pdfContent = baos.toString("UTF-8");
String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
// check for pdf-a schema extension
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
@@ -143,7 +144,7 @@ public class BackwardCompatibilityTest extends TestCase implements IExportableTr
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos);
ze.close();
String pdfContent = baos.toString("UTF-8");
String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
// check for pdf-a schema extension
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
@@ -316,7 +317,7 @@ public class BackwardCompatibilityTest extends TestCase implements IExportableTr
//
public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
Payment P = new Payment();
IZUGFeRDTradeSettlementPayment[] allP = new Payment[1];
allP[0] = P;

View File

@@ -22,16 +22,7 @@ import junit.framework.Test;
import junit.framework.TestSuite;
import junit.framework.TestCase;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.mustangproject.XMLTools;
public class BaseTest extends TestCase {

View File

@@ -6,17 +6,18 @@ import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.mustangproject.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
/***
* tests the linecalculator and transactioncalculator classes
*
*/
public class CalculationTest {
private static final Logger LOGGER = LoggerFactory.getLogger (CalculationTest.class);
@Test
public void testLineCalculator_simpleAmounts_resultInValidVATAmount() {
@@ -92,7 +93,7 @@ public class CalculationTest {
invoice.setDeliveryDate(sqlDate.parse("2020-12-31"));
invoice.setDueDate(sqlDate.parse("2021-01-15"));
} catch (Exception e) {
Logger.getLogger(CalculationTest.class.getName()).log(Level.SEVERE, null, e);
LOGGER.error("Failed to set dates", e);
}

View File

@@ -45,7 +45,7 @@ import java.util.GregorianCalendar;
import static org.xmlunit.assertj.XmlAssert.assertThat;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class DXTest extends MustangReaderTestCase implements IExportableTransaction {
public class DXTest extends MustangReaderTestCase {
final String TARGET_PDF = "./target/testout-DX.pdf";
final String TARGET_XML = "./target/testout-DX.xml";

View File

@@ -21,12 +21,9 @@
*/
package org.mustangproject.ZUGFeRD;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import junit.framework.TestCase;
import org.assertj.core.util.Lists;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import org.mustangproject.*;

View File

@@ -256,13 +256,13 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
"</ram:ApplicableHeaderTradeSettlement>\n" +
"</rsm:SupplyChainTradeTransaction>\n" +
"</rsm:CrossIndustryInvoice>";
zea1.setXML(ownZUGFeRDXML.getBytes("UTF-8"));
zea1.setXML(ownZUGFeRDXML.getBytes(StandardCharsets.UTF_8));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
zea1.disableAutoClose(true);
zea1.export(TARGET_PDF);
zea1.export(baos);
zea1.close();
String pdfContent = baos.toString("UTF-8");
String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
assertFalse(pdfContent.indexOf("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>") == -1);
@@ -437,14 +437,14 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
+ "<ram:Name>Heiße Luft pro Liter</ram:Name>\n" + "<ram:Description/>\n"
+ "</ram:SpecifiedTradeProduct>\n" + "</ram:IncludedSupplyChainTradeLineItem>\n"
+ "</rsm:SpecifiedSupplyChainTradeTransaction>\n" + "</rsm:CrossIndustryDocument>";
zea1.setXML(ownZUGFeRDXML.getBytes("UTF-8"));
zea1.setXML(ownZUGFeRDXML.getBytes(StandardCharsets.UTF_8));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
zea1.disableAutoClose(true);
zea1.export(TARGET_PDF);
zea1.export(baos);
zea1.close();
String pdfContent = baos.toString("UTF-8");
String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>BASIC</zf:ConformanceLevel>") == -1);

View File

@@ -21,6 +21,7 @@ package org.mustangproject.ZUGFeRD;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.xmpbox.XMPMetadata;
@@ -42,7 +43,7 @@ import java.util.GregorianCalendar;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
protected class EasyRecipientTradeParty extends RecipientTradeParty implements IZUGFeRDExportableTradeParty {
protected class EasyRecipientTradeParty extends RecipientTradeParty {
// Not testing extended profile here, lineThree not possible
@Override
public String getAdditionalAddressExtension() {
@@ -252,7 +253,7 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
setupPdfUnderTest(SOURCE_PDF, TARGET_PDF);
// now check the contents
PDDocument doc = PDDocument.load(new File(TARGET_PDF));
PDDocument doc = Loader.loadPDF(new File(TARGET_PDF));
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
assertNotNull("The pdf must contain XMPMetadata", meta);
@@ -262,7 +263,7 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
DomXmpParser xmpParser = new DomXmpParser();
XMPMetadata xmp = xmpParser.parse(xmpBytes);
PDFAIdentificationSchema pdfai = xmp.getPDFIdentificationSchema();
PDFAIdentificationSchema pdfai = xmp.getPDFAIdentificationSchema();
assertNotNull("The pdf must contain a PDFIdentificationSchema", pdfai);
assertTrue("The PDF/A conformance must be A, B or U",

View File

@@ -21,6 +21,7 @@ package org.mustangproject.ZUGFeRD;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
@@ -38,6 +39,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -328,13 +330,13 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
}
private void checkPdfA3B(File tempFile) throws IOException, InvalidPasswordException {
try (PDDocument doc = PDDocument.load(tempFile)) {
try (PDDocument doc = Loader.loadPDF(tempFile)) {
PDMetadata metadata = doc.getDocumentCatalog().getMetadata();
InputStream exportXMPMetadata = metadata.exportXMPMetadata();
byte[] xmpBytes = new byte[exportXMPMetadata.available()];
exportXMPMetadata.read(xmpBytes);
final XMPMetadata xmp = new DomXmpParser().parse(xmpBytes);
PDFAIdentificationSchema pdfaid = xmp.getPDFIdentificationSchema();
PDFAIdentificationSchema pdfaid = xmp.getPDFAIdentificationSchema();
assertEquals(pdfaid.getPart().intValue(), 3);
assertEquals(pdfaid.getConformance(), "U");
} catch (XmpParsingException e) {
@@ -367,7 +369,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos);
ze.close();
String pdfContent = baos.toString("UTF-8");
String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
// check for pdf-a schema extension
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
@@ -411,7 +413,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos);
ze.close();
String pdfContent = baos.toString("UTF-8");
String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.BASIC) >= 0);
assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.EXTENDED) >= 0);
assertTrue(pdfContent.indexOf(DocumentContextParameterTypeConstants.COMFORT) >= 0);
@@ -447,7 +449,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos);
ze.close();
String pdfContent = baos.toString("UTF-8");
String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
// check for pdf-a schema extension
assertFalse(pdfContent.indexOf("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>") == -1);

View File

@@ -28,7 +28,6 @@ import org.junit.runners.MethodSorters;
import org.mustangproject.*;
import javax.xml.xpath.XPathExpressionException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
@@ -42,7 +41,7 @@ import java.util.Date;
import java.util.GregorianCalendar;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class OXTest extends MustangReaderTestCase implements IExportableTransaction {
public class OXTest extends MustangReaderTestCase {
final String TARGET_PDF = "./target/testout-OX.pdf";
final String TARGET_PDF_EDGE = "./target/testout-OX-edge.pdf";
final String TARGET_XML = "./target/testout-OX.xml";

View File

@@ -0,0 +1,87 @@
/**
* *********************************************************************
* <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.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import org.mustangproject.*;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Date;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class PreValidationTest extends TestCase {
final String TARGET_PDF = "./target/testout-Preval.pdf";
final String SOURCE_PDF = "/veraPDFtestsuite6-7-11-t01-fail-a.pdf";
public void testFailIgnore() {
// the writing part
boolean hasEx = false;
try (InputStream source = this.getClass()
.getResourceAsStream(SOURCE_PDF)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2)
.load(source);
ze.setTransaction(createInvoice());
ze.export(TARGET_PDF);
} catch (IOException e) {
hasEx = true;
}
assertTrue(hasEx);
hasEx = false;
try (InputStream source = this.getClass()
.getResourceAsStream(SOURCE_PDF)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors().load(source);
ze.setProducer("My Application").setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).
setTransaction(createInvoice());
ze.export(TARGET_PDF);
} catch (IOException e) {
hasEx = true;
}
assertFalse(hasEx);
}
private Invoice createInvoice() {
String orgname = "Test company";
String number = "123";
String amountStr = "1.00";
BigDecimal amount = new BigDecimal(amountStr);
return new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("DE4711").addVATID("DE0815").setEmail("info@example.org").setContact(new Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new BankDetails("DE12500105170648489890", "COBADEFXXX")))
.setRecipient(new TradeParty("Theodor Est", "Bahnstr. 42", "88802", "Spielkreis", "DE"))
.setReferenceNumber("991-01484-64")//leitweg-id
// not using any VAT, this is also a test of zero-rated goods:
.setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO), amount, new BigDecimal(1.0)));
}
}

View File

@@ -23,13 +23,10 @@ package org.mustangproject.ZUGFeRD;
import junit.framework.TestCase;
import org.mustangproject.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
/***
* This is a test to confirm the minimum steps to implement a interface are still sufficient

View File

@@ -1,6 +1,8 @@
package org.mustangproject.ZUGFeRD;
import junit.framework.TestCase;
import org.junit.Ignore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -9,6 +11,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@Ignore
public class ResourceCase extends TestCase {
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceCase.class.getCanonicalName()); // log output is

View File

@@ -22,15 +22,16 @@ import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This test utility class is providing usability functions to test file resources
*/
public class ResourceUtilities {
private static final Logger LOG = Logger.getLogger(ResourceUtilities.class.getName());
private static final Logger LOGGER = LoggerFactory.getLogger (ResourceUtilities.class);
/**
* Loading a File into a String using a certain encoding and file path
@@ -73,7 +74,7 @@ public class ResourceUtilities {
uri = ResourceUtilities.class.getClassLoader().getResource(relativeFilePath).toURI();
uri = new URI(toExternalForm(uri));
} catch (URISyntaxException ex) {
LOG.log(Level.SEVERE, null, ex);
LOGGER.error("Failed to parse URI", ex);
}
if (uri == null) {
throw new FileNotFoundException("Could not find the file '" + relativeFilePath + "'!");
@@ -129,7 +130,7 @@ public class ResourceUtilities {
try {
filepath = ResourceUtilities.class.getClassLoader().getResource("").toURI().getPath() + relativeFilePath;
} catch (URISyntaxException ex) {
LOG.log(Level.SEVERE, null, ex);
LOGGER.error("Failed to parse URI", ex);
}
return new File(filepath);
}
@@ -142,7 +143,7 @@ public class ResourceUtilities {
try {
testFolder = ResourceUtilities.class.getClassLoader().getResource("").toURI().getPath();
} catch (URISyntaxException ex) {
LOG.log(Level.SEVERE, null, ex);
LOGGER.error("Failed to parse URI", ex);
}
return testFolder;
}
@@ -206,7 +207,7 @@ public class ResourceUtilities {
try {
ret = new URI(sb.toString()).toASCIIString();
} catch (URISyntaxException ex) {
LOG.log(Level.SEVERE, null, ex);
LOGGER.error("Failed to parse URI", ex);
}
return ret;
}

View File

@@ -21,13 +21,12 @@
*/
package org.mustangproject.ZUGFeRD;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.Date;
import org.assertj.core.api.Assertions;
@@ -41,6 +40,8 @@ import org.mustangproject.Item;
import org.mustangproject.Product;
import org.mustangproject.TradeParty;
import javax.xml.xpath.XPathExpressionException;
public class UBLTest extends ResourceCase {
final String TARGET_XML = "./target/testout-1Lieferschein.xml";
@@ -89,7 +90,7 @@ public class UBLTest extends ResourceCase {
final ByteArrayOutputStream baos=new ByteArrayOutputStream();
oe.export(baos);
final String theXML = baos.toString("UTF-8");
final String theXML = baos.toString(StandardCharsets.UTF_8);
assertTrue(theXML.contains("<DespatchAdvice"));
Files.write(Paths.get(TARGET_XML), theXML.getBytes(StandardCharsets.UTF_8));
} catch (final IOException e) {
@@ -98,4 +99,76 @@ public class UBLTest extends ResourceCase {
}
public void testEdgeInvoiceImportUBL() {
File UBLinputFile = getResourceAsFile("ubl/01.01a-INVOICE.ubl.xml");
boolean hasExceptions = false;
ZUGFeRDInvoiceImporter zii = null;
Invoice invoice = null;
try {
zii = new ZUGFeRDInvoiceImporter(new FileInputStream(UBLinputFile));
invoice = zii.extractInvoice();
} catch (XPathExpressionException | ParseException | FileNotFoundException e) {
hasExceptions = true;
}
assertFalse(hasExceptions);
// Reading ZUGFeRD
assertEquals(new BigDecimal("288.79"), invoice.getZFItems()[0].getPrice());
assertEquals("04011000-12345-03", invoice.getReferenceNumber());
assertEquals("seller@email.de", invoice.getSender().getContact().getEMail());
assertEquals("12345", invoice.getRecipient().getZIP());
assertEquals("DE75512108001245126199", invoice.getSender().getBankDetails().get(0).getIBAN());
}
/* public void testInvoiceImportOtherUBL() {
File UBLinputFile = getResourceAsFile("ubl/EN16931_1_Teilrechnung.ubl.xml");
// File UBLinputFile = getResourceAsFile("ubl/EN16931_2_Teilrechnung.ubl.xml");
/* File UBLinputFile = getResourceAsFile("ubl/EN16931_AbweichenderZahlungsempf.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Betriebskostenabrechnung.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Einfach.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Einfach_DueDate.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Einfach_negativePaymentDue.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Elektron.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_ElektronischeAdresse.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Gutschrift.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Haftpflichtversicherung_Versicherungssteuer.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Innergemeinschaftliche_Lieferungen.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Kraftfahrversicherung_Bruttopreise.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Miete.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_OEPNV.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Physiotherapeut.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Rabatte.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Rechnungskorrektur.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_RechnungsUebertragung.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Reisekostenabrechnung.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_Sachversicherung_berechneter_Steuersatz.ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/EN16931_SEPA_Prenotification.ubl.xml");
boolean hasExceptions = false;
ZUGFeRDInvoiceImporter zii = null;
Invoice invoice = null;
try {
zii = new ZUGFeRDInvoiceImporter(new FileInputStream(UBLinputFile));
invoice = zii.extractInvoice();
} catch (XPathExpressionException | ParseException | FileNotFoundException e) {
hasExceptions = true;
}
assertFalse(hasExceptions);
// Reading ZUGFeRD
assertEquals(new BigDecimal("288.79"), invoice.getZFItems()[0].getPrice());
assertEquals("04011000-12345-03", invoice.getReferenceNumber());
assertEquals("seller@email.de", invoice.getSender().getContact().getEMail());
assertEquals("12345", invoice.getRecipient().getZIP());
assertEquals("DE75512108001245126199", invoice.getSender().getBankDetails().get(0).getIBAN());
}*/
}

View File

@@ -19,24 +19,9 @@
*********************************************************************** */
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 {

View File

@@ -19,16 +19,12 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import org.apache.fop.apps.*;
import org.apache.xmlgraphics.util.MimeConstants;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import org.mustangproject.CII.CIIToUBL;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -63,19 +59,20 @@ public class VisualizationTest extends ResourceCase {
fail("TransformerException should not happen: "+e.getMessage());
} catch (IOException e) {
fail("IOException should not happen: "+e.getMessage());
}
} catch (ParserConfigurationException e) {
fail("ParserConfigurationException should not happen: "+e.getMessage());
} catch (SAXException e) {
fail("SAXException should not happen: "+e.getMessage());
}
assertNotNull(result);
assertNotNull(result);
// Reading ZUGFeRD
assertEquals(expected, result);
}
public void testUBLCreditNoteVisualizationBasic() {
// the writing part
CIIToUBL c2u = new CIIToUBL();
String sourceFilename = "factur-x.xml";
File UBLinputFile = getResourceAsFile("ubl-creditnote.xml");
String expected = null;
@@ -85,10 +82,10 @@ public class VisualizationTest extends ResourceCase {
/* remove file endings so that tests can also pass after checking
out from git with arbitrary options (which may include CSRF changes)
*/
result = zvi.visualize(UBLinputFile.getAbsolutePath(),ZUGFeRDVisualizer.Language.EN).replace("\r","").replace("\n","");
result = zvi.visualize(UBLinputFile.getAbsolutePath(),ZUGFeRDVisualizer.Language.EN).replace("\r","").replace("\n","").replace(" ","").replace("\t","");
File expectedResult=getResourceAsFile("factur-x-vis-ubl-creditnote.en.html");
expected = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8).replace("\r","").replace("\n","");
expected = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8).replace("\r","").replace("\n","").replace(" ","").replace("\t","");
// remove linebreaks as well...
} catch (UnsupportedOperationException e) {
@@ -99,20 +96,21 @@ public class VisualizationTest extends ResourceCase {
fail("TransformerException should not happen: "+e.getMessage());
} catch (IOException e) {
fail("IOException should not happen: "+e.getMessage());
} catch (ParserConfigurationException e) {
fail("ParserConfigurationException should not happen: "+e.getMessage());
} catch (SAXException e) {
fail("SAXException should not happen: "+e.getMessage());
}
assertNotNull(result);
assertNotNull(result);
// Reading ZUGFeRD
assertEquals(expected, result);
}
public void testUBLVisualizationBasic() {
// the writing part
CIIToUBL c2u = new CIIToUBL();
String sourceFilename = "factur-x.xml";
File UBLinputFile = getResourceAsFile("01.01a-INVOICE_ubl.xml");
File UBLinputFile = getResourceAsFile("ubl/01.01a-INVOICE.ubl.xml");
String expected = null;
String result = null;
@@ -135,11 +133,14 @@ public class VisualizationTest extends ResourceCase {
fail("TransformerException should not happen: "+e.getMessage());
} catch (IOException e) {
fail("IOException should not happen: "+e.getMessage());
}
} catch (ParserConfigurationException e) {
fail("ParserConfigurationException should not happen: "+e.getMessage());
} catch (SAXException e) {
fail("SAXException should not happen: "+e.getMessage());
}
assertNotNull(result);
assertNotNull(result);
// Reading ZUGFeRD
assertEquals(expected, result);
}

View File

@@ -32,9 +32,6 @@ import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import static org.xmlunit.assertj.XmlAssert.assertThat;
@@ -88,10 +85,11 @@ public class XRTest extends TestCase {
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
.setSender(new TradeParty(orgname,"teststr","55232","teststadt","DE").setEmail("sender@example.com").addTaxID("DE4711").addVATID("DE0815").setContact(new Contact("Hans Test","+49123456789","test@example.org")).addBankDetails(new BankDetails("DE12500105170648489890","COBADEFXXX")))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setEmail("recipient@sample.org"))
.addCashDiscount(new CashDiscount(new BigDecimal(2),7))
.addCashDiscount(new CashDiscount(new BigDecimal(3),14))
.setReferenceNumber("991-01484-64")//leitweg-id
// not using any VAT, this is also a test of zero-rated goods:
.setNumber(number).setPaymentTermDescription("#SKONTO#TAGE=14#PROZENT=2.25#\n" +
"#SKONTO#TAGE=28#PROZENT=1.00#\n").addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO), amount, new BigDecimal(1.0)))
.setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO), amount, new BigDecimal(1.0)))
.embedFileInXML(fe1);
@@ -101,6 +99,7 @@ public class XRTest extends TestCase {
zf2p.generateXML(i);
String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8);
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
assertTrue(theXML.contains("#SKONTO#"));
assertThat(theXML).valueByXPath("count(//*[local-name()='IncludedSupplyChainTradeLineItem'])")
.asInt()
.isEqualTo(1); //2 errors are OK because there is a known bug

View File

@@ -37,7 +37,7 @@ import junit.framework.Test;
import junit.framework.TestSuite;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ZF2EdgeTest extends MustangReaderTestCase implements IExportableTransaction {
public class ZF2EdgeTest extends MustangReaderTestCase {
final String TARGET_PDF = "./target/testout-ZF2newEdge.pdf";
protected class EdgeProduct implements IZUGFeRDExportableProduct {
@@ -293,12 +293,15 @@ public class ZF2EdgeTest extends MustangReaderTestCase implements IExportableTra
// the writing part
try (InputStream SOURCE_PDF = this.getClass()
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)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();ze.ignorePDFAErrors();
ze.load(SOURCE_PDF);
ze.setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile(Profiles.getByName("Extended"));
ze.setTransaction(this);
String theXML = new String(ze.getProvider().getXML(), StandardCharsets.UTF_8);
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
@@ -322,7 +325,7 @@ public class ZF2EdgeTest extends MustangReaderTestCase implements IExportableTra
assertTrue(resultXML.contains("<ram:IssuerAssignedID>123</ram:IssuerAssignedID>"));
// Reading ZUGFeRD
assertEquals("337.60", zi.getAmount());;
assertEquals("337.60", zi.getAmount());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
try {

View File

@@ -21,9 +21,11 @@
*/
package org.mustangproject.ZUGFeRD;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -35,9 +37,6 @@ import org.junit.runners.MethodSorters;
import junit.framework.TestCase;
import org.mustangproject.ZUGFeRD.model.EventTimeCodeTypeConstants;
import org.xmlunit.builder.Input;
import org.xmlunit.xpath.JAXPXPathEngine;
import org.xmlunit.xpath.XPathEngine;
import javax.xml.xpath.XPathExpressionException;
@@ -54,6 +53,7 @@ public class ZF2PushTest extends TestCase {
final String TARGET_CHARGESALLOWANCESPDF = "./target/testout-ZF2PushChargesAllowances.pdf";
final String TARGET_RELATIVECHARGESALLOWANCESPDF = "./target/testout-ZF2PushRelativeChargesAllowances.pdf";
final String TARGET_ATTACHMENTSPDF = "./target/testout-ZF2PushAttachments.pdf";
final String TARGET_BANKPDF = "./target/testout-ZF2PushBank.pdf";
final String TARGET_PUSHEDGE = "./target/testout-ZF2PushEdge.pdf";
final String TARGET_INTRACOMMUNITYSUPPLYPDF = "./target/testout-ZF2PushIntraCommunitySupply.pdf";
final String TARGET_REVERSECHARGEPDF = "./target/testout-ZF2PushReverseCharge.pdf";
@@ -68,28 +68,29 @@ public class ZF2PushTest extends TestCase {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
BigDecimal price = new BigDecimal(priceStr);
try (InputStream SOURCE_PDF = this.getClass()
try {
InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20201121_508blanko.pdf");
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors();
ze.load(SOURCE_PDF);
ze.setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2);
ze.setTransaction(new Invoice().setDueDate(sdf.parse("2020-12-12")).setIssueDate(sdf.parse("2020-11-21")).setDeliveryDate(sdf.parse("2020-11-10"))
.setSender(new TradeParty(orgname, "Ecke 12", "12345", "Stadthausen", "DE").addBankDetails(new BankDetails("DE88200800000970375700", "COBADEFFXXX").setAccountName("Max Mustermann")).addVATID("DE136695976"))
.setRecipient(new TradeParty("Theodor Est", "Bahnstr. 42", "88802", "Spielkreis", "DE")
.setContact(new Contact("Ingmar N. Fo", "(555) 23 78-23", "info@localhost.local")).setID("2"))
.setNumber(number)
.setReferenceNumber("AB321")
.addItem(new Item(new Product("Design (hours)", "Of a sample invoice", "HUR", new BigDecimal(7)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Ballons", "various colors, ~2000ml", "H87", new BigDecimal(19)), new BigDecimal("0.79"), new BigDecimal(400.0)))
.addItem(new Item(new Product("Hot air „heiße Luft“ (litres)", "", "LTR", new BigDecimal(19)), new BigDecimal("0.025"), new BigDecimal(800.0)))
.setSender(new TradeParty(orgname, "Ecke 12", "12345", "Stadthausen", "DE").addBankDetails(new BankDetails("DE88200800000970375700", "COBADEFFXXX").setAccountName("Max Mustermann")).addVATID("DE136695976"))
.setRecipient(new TradeParty("Theodor Est", "Bahnstr. 42", "88802", "Spielkreis", "DE")
.setContact(new Contact("Ingmar N. Fo", "(555) 23 78-23", "info@localhost.local")).setID("2"))
.setNumber(number)
.setReferenceNumber("AB321")
.addItem(new Item(new Product("Design (hours)", "Of a sample invoice", "HUR", new BigDecimal(7)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Ballons", "various colors, ~2000ml", "H87", new BigDecimal(19)), new BigDecimal("0.79"), new BigDecimal(400.0)))
.addItem(new Item(new Product("Hot air „heiße Luft“ (litres)", "", "LTR", new BigDecimal(19)), new BigDecimal("0.025"), new BigDecimal(800.0)))
);
ze.export(TARGET_PDF);
} catch (IOException | ParseException e) {
fail("Exception should not be raised in testPushExport");
fail("Exception should not be raised");
}
// now check the contents (like MustangReaderTest)
@@ -121,24 +122,26 @@ public class ZF2PushTest extends TestCase {
String priceStr = "1.00";
String taxID = "9990815";
BigDecimal price = new BigDecimal(priceStr);
try (InputStream SOURCE_PDF = this.getClass()
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)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors();
ze.load(SOURCE_PDF);
ze.setProducer("My Application").setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2);
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)), price, new BigDecimal(1.0)))
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID(taxID).addVATID("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)), price, 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");
fail("IOException should not be raised");
}
// now check the contents (like MustangReaderTest)
@@ -158,6 +161,47 @@ public class ZF2PushTest extends TestCase {
}
}
public void testBankTransferExport() {
String orgname = "Test company";
String number = "123";
String priceStr = "1.00";
String taxID = "9990815";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors().load(SOURCE_PDF);
ze.setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2);
String IBAN = "DE999888777";
String BIC = "COBADEFXXX";
BankDetails bd = new BankDetails(IBAN, BIC);
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addBankDetails(bd).addTaxID(taxID).addVATID("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)), price, new BigDecimal(1.0)))
);
String theXML = new String(ze.getProvider().getXML());
Invoice read = new Invoice();
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new ByteArrayInputStream(theXML.getBytes(StandardCharsets.UTF_8)));
zii.extractInto(read);
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
//assertEquals(IBAN,read.getSender().getBankDetails().get(0).getIBAN());
ze.export(TARGET_BANKPDF);
} catch (IOException e) {
fail("IOException should not be raised");
} catch (XPathExpressionException e) {
fail("XPathException should not be raised");
} catch (ParseException e) {
fail("ParseException should not be raised");
}
}
public void testItemChargesAllowancesExport() {
@@ -166,21 +210,23 @@ public class ZF2PushTest extends TestCase {
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
try (InputStream SOURCE_PDF = this.getClass()
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)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors().load(SOURCE_PDF);
ze.setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("extended");
// 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"))))
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(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").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"))))
);
@@ -188,7 +234,7 @@ public class ZF2PushTest extends TestCase {
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_ITEMCHARGESALLOWANCESPDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
fail("IOException should not be raised");
}
// now check the contents (like MustangReaderTest)
@@ -217,32 +263,34 @@ public class ZF2PushTest extends TestCase {
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
try (InputStream SOURCE_PDF = this.getClass()
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)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors().load(SOURCE_PDF);
ze.setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("extended");
// 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").addVATID("DE0815")).setOwnTaxID("4711")
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0816").setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562")))
.setDeliveryAddress(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0816"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addVATID("DE0815").addTaxID ("4711"))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0816").setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562")))
.setDeliveryAddress(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0816"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_INTRACOMMUNITYSUPPLYPDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
fail("IOException should not be raised");
}
// now check the contents (like MustangReaderTest)
@@ -270,28 +318,31 @@ public class ZF2PushTest extends TestCase {
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
try (InputStream SOURCE_PDF = this.getClass()
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)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors().load(SOURCE_PDF);
ze.setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("extended");
// 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").addVATID("DE0815")).setOwnTaxID("4711").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0816").setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562"))).setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addVATID("DE0815").addTaxID("4711")).setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0816").setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562"))).setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_REVERSECHARGEPDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
fail("IOException should not be raised");
}
// now check the contents (like MustangReaderTest)
@@ -312,32 +363,36 @@ public class ZF2PushTest extends TestCase {
}
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()
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)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors()
.load(SOURCE_PDF);
ze.setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile(Profiles.getByName("en16931"));
ze.setTransaction(new Invoice().setCurrency("CHF").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)))
.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)))
ze.setTransaction(new Invoice().setCurrency("CHF").setDueDate(new Date()).setIssueDate(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")).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");
fail("IOException should not be raised");
}
// now check the contents (like MustangReaderTest)
@@ -371,29 +426,34 @@ public class ZF2PushTest extends TestCase {
String priceStr = "1.00";
String taxID = "9990815";
BigDecimal price = new BigDecimal(priceStr);
try (InputStream SOURCE_PDF = this.getClass()
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)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors()
.load(SOURCE_PDF);
ze.setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile(Profiles.getByName("extended"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
SchemedID gtin=new SchemedID("0160","2001015001325");
SchemedID gln=new SchemedID("0088","4304171000002");
SchemedID gtin = new SchemedID("0160", "2001015001325");
SchemedID gln = new SchemedID("0088", "4304171000002");
ze.setTransaction(new Invoice().setCurrency("CHF").addNote("document level 1/2").addNote("document level 2/2").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
.setSellerOrderReferencedDocumentID("9384").setBuyerOrderReferencedDocumentID("28934")
.setDetailedDeliveryPeriod(new SimpleDateFormat("yyyyMMdd").parse(occurrenceFrom), new SimpleDateFormat("yyyyMMdd").parse(occurrenceTo))
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID(taxID).setEmail("sender@test.org").setID("0009845"))
.setDeliveryAddress(new TradeParty("just the other side of the street", "teststr.12a", "55232", "Entenhausen", "DE").addVATID("DE47110"))
.setContractReferencedDocument(contractID)
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addGlobalID(gln).setEmail("recipient@test.org").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE").setFax("++49555123456")).setAdditionalAddress("Hinterhaus 3"))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).addReferencedLineID("xxx").addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15")))
.addCharge(new Charge(new BigDecimal(0.5)).setReason("quick delivery charge").setTaxPercent(new BigDecimal(16)))
.addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16)))
.setDeliveryDate(sdf.parse("2020-11-02")).setOwnVATID("DE0815").setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE)
.setSellerOrderReferencedDocumentID("9384").setBuyerOrderReferencedDocumentID("28934")
.setDetailedDeliveryPeriod(new SimpleDateFormat("yyyyMMdd").parse(occurrenceFrom), new SimpleDateFormat("yyyyMMdd").parse(occurrenceTo))
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID(taxID).setEmail("sender@test.org").setID("0009845").addVATID("DE0815"))
.setDeliveryAddress(new TradeParty("just the other side of the street", "teststr.12a", "55232", "Entenhausen", "DE").addVATID("DE47110"))
.setContractReferencedDocument(contractID)
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addGlobalID(gln).setEmail("recipient@test.org").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE").setFax("++49555123456")).setAdditionalAddress("Hinterhaus 3"))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).addReferencedLineID("xxx").addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15")))
.addCharge(new Charge(new BigDecimal(0.5)).setReason("quick delivery charge").setTaxPercent(new BigDecimal(16)))
.addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16)))
.addCashDiscount(new CashDiscount(new BigDecimal(2), 14))
.setDeliveryDate(sdf.parse("2020-11-02")).setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE)
);
} catch (ParseException e) {
e.printStackTrace();
@@ -403,7 +463,7 @@ public class ZF2PushTest extends TestCase {
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_PUSHEDGE);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
fail("IOException should not be raised");
}
// now check the contents (like MustangReaderTest)
@@ -412,9 +472,9 @@ public class ZF2PushTest extends TestCase {
assertFalse(zi.getUTF8().contains("<ram:IBANID>")); // maybe add a direct debit mandate to the class in the future then this would fail
assertTrue(zi.getUTF8().contains("Hinterhaus"));
assertThat(zi.getUTF8()).valueByXPath("//*[local-name()='BuyerTradeParty']/*[local-name()='GlobalID'][@schemeID=0088]").asString()
.isEqualTo("4304171000002");
.isEqualTo("4304171000002");
assertThat(zi.getUTF8()).valueByXPath("//*[local-name()='SpecifiedTradeProduct']/*[local-name()='GlobalID'][@schemeID=0160]").asString()
.isEqualTo("2001015001325");
.isEqualTo("2001015001325");
assertTrue(zi.getUTF8().contains("2001015001325"));
assertTrue(zi.getUTF8().contains("4304171000002"));
assertTrue(zi.getUTF8().contains("0088"));
@@ -431,9 +491,10 @@ public class ZF2PushTest extends TestCase {
assertTrue(zi.getUTF8().contains("DE4711")); // the VAT ID should be there...
assertFalse(zi.getUTF8().contains("DE47110")); // but not the VAT ID of the shiptotradeparty
assertTrue(zi.getUTF8().contains("document level 2/2"));
assertFalse(zi.getUTF8().contains("++49555123456")); // in profile EN16931 contact fax number is not allowed
assertTrue(zi.getUTF8().contains("++49555123456"));
assertTrue(zi.getUTF8().contains("Cash Discount")); // default description for cash discounts
assertThat(zi.getUTF8()).valueByXPath("//*[local-name()='ApplicableTradeTax']/*[local-name()='DueDateTypeCode']").asString()
.isEqualTo(EventTimeCodeTypeConstants.PAYMENT_DATE);
.isEqualTo(EventTimeCodeTypeConstants.PAYMENT_DATE);
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_PUSHEDGE);
try {
@@ -444,15 +505,14 @@ public class ZF2PushTest extends TestCase {
} catch (XPathExpressionException e) {
fail("XPathExpressionException should not be raised in testEdgeExport");
fail("XPathExpressionException should not be raised");
} catch (ParseException e) {
fail("ParseException should not be raised in testEdgeExport");
fail("ParseException should not be raised");
/* a parseException would also be fired if the calculated grand total does not
match the read grand total */
}
}
public void testAllowancesExport() {
@@ -460,23 +520,27 @@ public class ZF2PushTest extends TestCase {
String orgname = "Test company";
String number = "123";
BigDecimal qty = new BigDecimal("20");
try (InputStream SOURCE_PDF = this.getClass()
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)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.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)), new BigDecimal(500.0), qty).addAllowance(new Allowance(new BigDecimal(300)).setTaxPercent(new BigDecimal(19))))
.addAllowance(new Allowance(new BigDecimal(600)).setTaxPercent(new BigDecimal(19)))
ze.setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile(Profiles.getByName("en16931"));
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(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")).setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(500.0), qty).addAllowance(new Allowance(new BigDecimal(300)).setTaxPercent(new BigDecimal(19))))
.addAllowance(new Allowance(new BigDecimal(600)).setTaxPercent(new BigDecimal(19)))
);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_ALLOWANCESPDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
fail("IOException should not be raised");
}
// now check the contents (like MustangReaderTest)
@@ -503,25 +567,29 @@ public class ZF2PushTest extends TestCase {
String number = "123";
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
try (InputStream SOURCE_PDF = this.getClass()
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)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors()
.load(SOURCE_PDF);
ze.setTransaction(new Invoice().setCurrency("CHF").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)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, 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)))
ze.setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile(Profiles.getByName("extended"));
ze.setTransaction(new Invoice().setCurrency("CHF").setDueDate(new Date()).setIssueDate(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")).setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, 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");
fail("IOException should not be raised");
}
// now check the contents (like MustangReaderTest)
@@ -555,23 +623,26 @@ public class ZF2PushTest extends TestCase {
String priceStr = "1.00";
BigDecimal price = new BigDecimal(priceStr);
BigDecimal qty = new BigDecimal(-1.0);
try (InputStream SOURCE_PDF = this.getClass()
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)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors()
.load(SOURCE_PDF);
ze.setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2);
// no due date, since we are not expecting money
Invoice i = new Invoice().setIssueDate(new Date()).setDetailedDeliveryPeriod(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, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty)).setCorrection("0815");
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty)).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");
fail("IOException should not be raised");
}
// now check the contents (like MustangReaderTest)
@@ -605,22 +676,26 @@ public class ZF2PushTest extends TestCase {
String priceStr = "1.00";
BigDecimal price = new BigDecimal(priceStr);
BigDecimal qty = new BigDecimal(1.0);
try (InputStream SOURCE_PDF = this.getClass()
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)) {
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors()
.load(SOURCE_PDF);
ze.
setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2);
Invoice i = new Invoice().setIssueDate(new Date()).setDueDate(new Date()).setDetailedDeliveryPeriod(new Date(), new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815").addBankDetails(new BankDetails("DE88200800000970375700", "COBADEFFXXX"))).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, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty)).setCreditNote();
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty)).setCreditNote();
ze.setTransaction(i);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_CREDITNOTEPDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
fail("IOException should not be raised");
}
// now check the contents (like MustangReaderTest)

View File

@@ -229,15 +229,14 @@ public class ZF2Test extends MustangReaderTestCase {
assertEquals(zi.getSellerTradePartyAddress().getCityName(), "Stadthausen");
final 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(), "");
assertEquals(li.get(0).getId().toString(), "1");
assertEquals(li.get(0).getProduct().getBuyerAssignedID(), "");
assertEquals(li.get(0).getProduct().getSellerAssignedID(), "");
assertEquals(li.get(0).getLineTotalAmount().toString(), "160.00");
assertEquals(li.get(0).getQuantity().toString(), "1.0000");
assertEquals(li.get(0).getProduct().getVATPercent().toString(), "7.00");
assertEquals(li.get(0).getProduct().getName(), "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung");
assertEquals(li.get(0).getProduct().getDescription(), "");
try {
assertEquals(zi.getVersion(), 2);

View File

@@ -21,16 +21,8 @@
*/
package org.mustangproject.ZUGFeRD;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
import org.mustangproject.Invoice;
import junit.framework.TestCase;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;
import java.io.*;
import java.math.BigDecimal;
@@ -39,7 +31,6 @@ import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Scanner;
/***
@@ -175,6 +166,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
}
public void testZF1Import() {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-MustangGnuaccountingBeispielRE-20171118_506zf1.pdf");

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cec="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>471102</cbc:ID>
<cbc:IssueDate>2018-03-05</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:Note>Rechnung gemäß Bestellung vom 01.03.2018.</cbc:Note>
<cbc:Note>#REG#Lieferant GmbH
Lieferantenstraße 20
80333 München
Deutschland
Geschäftsführer: Hans Muster
Handelsregisternummer: H A 123
</cbc:Note>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cbc:BuyerReference>04011000-12345-34</cbc:BuyerReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cac:PartyIdentification>
<cbc:ID schemeID="0088">4000001123452</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Lieferant GmbH</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Lieferantenstraße 20</cbc:StreetName>
<cbc:CityName>München</cbc:CityName>
<cbc:PostalZone>80333</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>201/113/40209</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>FC</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE123456789</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Lieferant GmbH</cbc:RegistrationName>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>Max Mustermann</cbc:Name>
<cbc:Telephone>+49891234567</cbc:Telephone>
<cbc:ElectronicMail>Max@Mustermann.de</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cac:PartyIdentification>
<cbc:ID>GE2020211</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Kunden AG Mitte</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Kundenstraße 15</cbc:StreetName>
<cbc:CityName>Frankfurt</cbc:CityName>
<cbc:PostalZone>69876</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Kunden AG Mitte</cbc:RegistrationName>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:Delivery>
<cbc:ActualDeliveryDate>2018-03-05</cbc:ActualDeliveryDate>
</cac:Delivery>
<cac:PaymentMeans>
<cbc:PaymentMeansCode name="Zahlung per SEPA Überweisung.">58</cbc:PaymentMeansCode>
<cac:PayeeFinancialAccount>
<cbc:ID>DE02120300000000202051</cbc:ID>
<cbc:Name>Kunden AG</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>BYLADEM1001</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
</cac:PaymentMeans>
<cac:PaymentTerms>
<cbc:Note>Zahlbar innerhalb 30 Tagen netto bis 04.04.2018, 3% Skonto innerhalb 10 Tagen bis 15.03.2018</cbc:Note>
</cac:PaymentTerms>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">56.87</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">275</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">19.25</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">198</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">37.62</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">473</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">473</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">529.87</cbc:TaxInclusiveAmount>
<cbc:AllowanceTotalAmount currencyID="EUR">0</cbc:AllowanceTotalAmount>
<cbc:ChargeTotalAmount currencyID="EUR">0</cbc:ChargeTotalAmount>
<cbc:PrepaidAmount currencyID="EUR">0</cbc:PrepaidAmount>
<cbc:PayableAmount currencyID="EUR">529.87</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="H87">20</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">198</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Trennblätter A4</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>TB100A4</cbc:ID>
</cac:SellersItemIdentification>
<cac:StandardItemIdentification>
<cbc:ID schemeID="0160">4012345001235</cbc:ID>
</cac:StandardItemIdentification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">9.9</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>2</cbc:ID>
<cbc:InvoicedQuantity unitCode="H87">50</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">275</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Joghurt Banane</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>ARNR2</cbc:ID>
</cac:SellersItemIdentification>
<cac:StandardItemIdentification>
<cbc:ID schemeID="0160">4000050986428</cbc:ID>
</cac:StandardItemIdentification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">5.5</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
</Invoice>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
<html xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xr="urn:ce.eu:en16931:2017:xoev-de:kosit:standard:xrechnung-1" xmlns:xrv="http://www.example.org/XRechnung-Viewer" lang="de">
<!DOCTYPE HTML>
<html xmlns:xr="urn:ce.eu:en16931:2017:xoev-de:kosit:standard:xrechnung-1" xmlns:xrv="http://www.example.org/XRechnung-Viewer" xmlns:xs="http://www.w3.org/2001/XMLSchema" lang="de">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<title>XRechnung</title>
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0">
<style>
@@ -1555,7 +1555,7 @@
<div class="boxzeile">
<div class="boxdaten legende ">Description:</div>
<div id="BT-154" title="BT-154" class="boxdaten wert">Processor: Intel Core 2 Duo SU9400 LV (1.4GHz). RAM:
3MB. Screen 1440x900</div>
3MB. Screen 1440x900</div>
</div>
<div class="boxzeile">
<div class="boxdaten legende ">Part number:</div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -177,7 +177,7 @@
</ram:DueDateDateTime>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>496.00</ram:LineTotalAmount>
<ram:LineTotalAmount>496.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>496.00</ram:TaxBasisTotalAmount>

View File

@@ -1,168 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:cec="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>RE-20201121/508</cbc:ID>
<cbc:IssueDate>2020-11-21</cbc:IssueDate>
<cbc:DueDate>2020-12-12</cbc:DueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cbc:BuyerReference>AB321</cbc:BuyerReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cac:PartyName>
<cbc:Name>Bei Spiel GmbH</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Ecke 12</cbc:StreetName>
<cbc:CityName>Stadthausen</cbc:CityName>
<cbc:PostalZone>12345</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE136695976</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Bei Spiel GmbH</cbc:RegistrationName>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cac:PartyIdentification>
<?xml version="1.0" encoding="UTF-8"?><Invoice xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cec="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>RE-20201121/508</cbc:ID>
<cbc:IssueDate>2020-11-21</cbc:IssueDate>
<cbc:DueDate>2020-12-12</cbc:DueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cbc:BuyerReference>AB321</cbc:BuyerReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cac:PostalAddress>
<cbc:StreetName>Ecke 12</cbc:StreetName>
<cbc:CityName>Stadthausen</cbc:CityName>
<cbc:PostalZone>12345</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE136695976</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Bei Spiel GmbH</cbc:RegistrationName>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cac:PartyIdentification>
<cbc:ID>2</cbc:ID>
</cac:PartyIdentification>
<cac:PostalAddress>
<cbc:StreetName>Bahnstr. 42</cbc:StreetName>
<cbc:CityName>Spielkreis</cbc:CityName>
<cbc:PostalZone>88802</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Theodor Est</cbc:RegistrationName>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:Delivery>
<cbc:ActualDeliveryDate>2020-11-10</cbc:ActualDeliveryDate>
</cac:Delivery>
<cac:PaymentMeans>
<cbc:PaymentMeansCode name="Bank transfer">42</cbc:PaymentMeansCode>
<cbc:PaymentID>RE-20201121/508</cbc:PaymentID>
<cac:PayeeFinancialAccount>
<cbc:ID>DE88200800000970375700</cbc:ID>
<cbc:Name>Max Mustermann</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>COBADEFFXXX</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
</cac:PaymentMeans>
<cac:PaymentTerms>
<cbc:Note>Zahlbar ohne Abzug bis 12.12.2020</cbc:Note>
</cac:PaymentTerms>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">75.04</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">160</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">11.2</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">336</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">63.84</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">496</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">496</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">571.04</cbc:TaxInclusiveAmount>
<cbc:AllowanceTotalAmount currencyID="EUR">0</cbc:AllowanceTotalAmount>
<cbc:ChargeTotalAmount currencyID="EUR">0</cbc:ChargeTotalAmount>
<cbc:PrepaidAmount currencyID="EUR">0</cbc:PrepaidAmount>
<cbc:PayableAmount currencyID="EUR">571.04</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="HUR">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">160</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Description>Of a sample invoice</cbc:Description>
<cbc:Name>Design (hours)</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">160</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="HUR">1</cbc:BaseQuantity>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:Amount currencyID="EUR">0</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">160</cbc:BaseAmount>
</cac:AllowanceCharge>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>2</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Theodor Est</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Bahnstr. 42</cbc:StreetName>
<cbc:CityName>Spielkreis</cbc:CityName>
<cbc:PostalZone>88802</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Theodor Est</cbc:RegistrationName>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:Delivery>
<cbc:ActualDeliveryDate>2020-11-10</cbc:ActualDeliveryDate>
</cac:Delivery>
<cac:PaymentMeans>
<cbc:PaymentMeansCode name="Bank transfer">42</cbc:PaymentMeansCode>
<cbc:PaymentID>RE-20201121/508</cbc:PaymentID>
<cac:PayeeFinancialAccount>
<cbc:ID>DE88200800000970375700</cbc:ID>
<cbc:Name>Max Mustermann</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>COBADEFFXXX</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
</cac:PaymentMeans>
<cac:PaymentTerms>
<cbc:Note>Zahlbar ohne Abzug bis 12.12.2020</cbc:Note>
</cac:PaymentTerms>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">75.04</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">160</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">11.2</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">336</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">63.84</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">496</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">496</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">571.04</cbc:TaxInclusiveAmount>
<cbc:AllowanceTotalAmount currencyID="EUR">0</cbc:AllowanceTotalAmount>
<cbc:ChargeTotalAmount currencyID="EUR">0</cbc:ChargeTotalAmount>
<cbc:PrepaidAmount currencyID="EUR">0</cbc:PrepaidAmount>
<cbc:PayableAmount currencyID="EUR">571.04</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="HUR">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">160</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Description>Of a sample invoice</cbc:Description>
<cbc:Name>Design (hours)</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">160</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="HUR">1</cbc:BaseQuantity>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>2</cbc:ID>
<cbc:InvoicedQuantity unitCode="H87">400</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">316</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Description>various colors, ~2000ml</cbc:Description>
<cbc:Name>Ballons</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">0.79</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="H87">1</cbc:BaseQuantity>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>3</cbc:ID>
<cbc:InvoicedQuantity unitCode="LTR">800</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">20</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Hot air „heiße Luft“ (litres)</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">0.025</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="LTR">1</cbc:BaseQuantity>
</cac:Price>
</cac:InvoiceLine>
<cbc:InvoicedQuantity unitCode="H87">400</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">316</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Description>various colors, ~2000ml</cbc:Description>
<cbc:Name>Ballons</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">0.79</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="H87">1</cbc:BaseQuantity>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:Amount currencyID="EUR">0</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">0.79</cbc:BaseAmount>
</cac:AllowanceCharge>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>3</cbc:ID>
<cbc:InvoicedQuantity unitCode="LTR">800</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">20</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Hot air „heiße Luft“ (litres)</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">0.025</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="LTR">1</cbc:BaseQuantity>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:Amount currencyID="EUR">0</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">0.025</cbc:BaseAmount>
</cac:AllowanceCharge>
</cac:Price>
</cac:InvoiceLine>
</Invoice>

View File

@@ -2,7 +2,8 @@
<ubl:Invoice xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.3</cbc:CustomizationID>
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>123456XX</cbc:ID>
<cbc:IssueDate>2016-04-04</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
@@ -11,6 +12,7 @@
<cbc:BuyerReference>04011000-12345-03</cbc:BuyerReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="EM">seller@email.de</cbc:EndpointID>
<cac:PartyName>
<cbc:Name>[Seller trading name]</cbc:Name>
</cac:PartyName>
@@ -42,6 +44,7 @@
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="EM">buyer@info.de</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID>[Buyer identifier]</cbc:ID>
</cac:PartyIdentification>

View File

@@ -0,0 +1,260 @@
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cec="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>471102</cbc:ID>
<cbc:IssueDate>2018-06-05</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:Note>Rechnung gemäß Bestellung Nr. 2018-471331 vom 01.03.2018.</cbc:Note>
<cbc:Note>#AAK#Es bestehen Rabatt- und Bonusvereinbarungen.</cbc:Note>
<cbc:Note>#REG#Lieferant GmbH
Lieferantenstraße 20
80333 München
Deutschland
Geschäftsführer: Hans Muster
Handelsregisternummer: H A 123
</cbc:Note>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cac:OrderReference>
<cbc:ID>2018-471331</cbc:ID>
</cac:OrderReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cac:PartyIdentification>
<cbc:ID schemeID="0088">4000001123452</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Lieferant GmbH</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Lieferantenstraße 20</cbc:StreetName>
<cbc:CityName>München</cbc:CityName>
<cbc:PostalZone>80333</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>201/113/40209</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>FC</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE123456789</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Lieferant GmbH</cbc:RegistrationName>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cac:PartyIdentification>
<cbc:ID>GE2020211</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Kunden AG Mitte</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Kundenstraße 15</cbc:StreetName>
<cbc:CityName>Frankfurt</cbc:CityName>
<cbc:PostalZone>69876</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Kunden AG Mitte</cbc:RegistrationName>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:Delivery>
<cbc:ActualDeliveryDate>2018-06-03</cbc:ActualDeliveryDate>
</cac:Delivery>
<cac:PaymentTerms>
<cbc:Note>Zahlbar innerhalb 30 Tagen netto bis 04.07.2018, 3% Skonto innerhalb 10 Tagen bis 15.06.2018</cbc:Note>
</cac:PaymentTerms>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReason>Sondernachlass</cbc:AllowanceChargeReason>
<cbc:Amount currencyID="EUR">1</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">10</cbc:BaseAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:AllowanceCharge>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReason>Sondernachlass</cbc:AllowanceChargeReason>
<cbc:Amount currencyID="EUR">8.07</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">115.3</cbc:BaseAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:AllowanceCharge>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>true</cbc:ChargeIndicator>
<cbc:AllowanceChargeReason>Versandkosten</cbc:AllowanceChargeReason>
<cbc:Amount currencyID="EUR">5.8</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">115.3</cbc:BaseAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:AllowanceCharge>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">20.16</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">113.03</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">7.91</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">64.46</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">12.25</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">180.76</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">177.49</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">197.65</cbc:TaxInclusiveAmount>
<cbc:AllowanceTotalAmount currencyID="EUR">9.07</cbc:AllowanceTotalAmount>
<cbc:ChargeTotalAmount currencyID="EUR">5.8</cbc:ChargeTotalAmount>
<cbc:PrepaidAmount currencyID="EUR">50</cbc:PrepaidAmount>
<cbc:PayableAmount currencyID="EUR">147.65</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:Note>Wir erlauben uns Ihnen folgende Positionen aus der Lieferung Nr. 2018-51112 in Rechnung zu stellen:</cbc:Note>
<cbc:InvoicedQuantity unitCode="MTK">3</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">10</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Description>300cm x 100 cm</cbc:Description>
<cbc:Name>Kunstrasen grün 3m breit</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>KR3M</cbc:ID>
</cac:SellersItemIdentification>
<cac:StandardItemIdentification>
<cbc:ID schemeID="0160">4012345001235</cbc:ID>
</cac:StandardItemIdentification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">3.3333</cbc:PriceAmount>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:Amount currencyID="EUR">0.6667</cbc:Amount>
</cac:AllowanceCharge>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>2</cbc:ID>
<cbc:Note>Bestellt wurden 5 kg Schweinesteak. Mit dieser Rechnung werden nur die bereits gelieferten Steaks berechnet. Die noch offenen 4 kg Schweinesteak werden separat geliefert und berechnet.</cbc:Note>
<cbc:InvoicedQuantity unitCode="KGM">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">5.5</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Description>Schweinesteak aus Deutschland</cbc:Description>
<cbc:Name>Schweinesteak</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>SFK5</cbc:ID>
</cac:SellersItemIdentification>
<cac:StandardItemIdentification>
<cbc:ID schemeID="0160">4000050986428</cbc:ID>
</cac:StandardItemIdentification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">5.5</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>3</cbc:ID>
<cbc:InvoicedQuantity unitCode="H87">20</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">109.8</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Mineralwasser Medium
12 x 1,0l PET
</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>GTRWA5</cbc:ID>
</cac:SellersItemIdentification>
<cac:StandardItemIdentification>
<cbc:ID schemeID="0160">4000001234561</cbc:ID>
</cac:StandardItemIdentification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>7</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">5.49</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>4</cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">20</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">55.46</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Pfand</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>PFA5</cbc:ID>
</cac:SellersItemIdentification>
<cac:StandardItemIdentification>
<cbc:ID schemeID="0160">4000001234578</cbc:ID>
</cac:StandardItemIdentification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">2.77</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
</Invoice>

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