Merge pull request #1 from ZUGFeRD/master

Merge
This commit is contained in:
Dominik Vogt
2020-06-17 12:07:37 +02:00
committed by GitHub
227 changed files with 843648 additions and 7326 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: [jstaerk]

117
.mvn/wrapper/MavenWrapperDownloader.java vendored Normal file
View File

@@ -0,0 +1,117 @@
/*
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}

BIN
.mvn/wrapper/maven-wrapper.jar vendored Normal file

Binary file not shown.

2
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View File

@@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

1
FUNDING.yml Normal file
View File

@@ -0,0 +1 @@
github: jstaerk

View File

@@ -1,3 +1,61 @@
2.0 todo
- verapdf as prevalidation
- remove jaxb
- visualization?
- factory for xrechnung
- new sample innvoice
- complete or discard read into push provider
- validate as library doc
- javadoc export
- prompt for source file for validation has to be pdf
- be able to disable "source pdf set to timeout"
- automated tests zuv/verapdf validate created library test files
- unify loggers
done
- 2.1 now default
- pushprovider
- new xrechnung profile
- german bank account numbers can no longer be specified (dropped in favor of IBAN and BIC)
- integrates validator
- validator now additionally supports xrechnung
- integrates mustangserver
- modular project setup
- getSellerTradePartyAddress (PR #157 ) thanks to aberndt-hub
- switched from eclipse to IntelliJ
- added ph-schematron-maven-plugin so that xrechnung xslt can be generated
- remove migration
- be able to recursively validate directories
1.7.7
=====
2020-05-26
- Refactored comparison operator for ChargeIndicator https://github.com/ZUGFeRD/mustangproject/pull/153
- ZUGFeRD2PullProvider needs getDueDate() although getPaymentTermDescription() is defined https://github.com/ZUGFeRD/mustangproject/pull/155
- #148 support additional documents for items
- #154 german VAT ID may not be used for sellercontact scheme id
1.7.6
=====
2020-02-06
- support different ship to address
- allow for diffent namespace prefixes #140
- include exemption reason if doing intra community supply
- allow different currencies also for ZF2 (#150)
- minor correction VAT exemptions
1.7.5
=====
2019-11-05
- support Sepa Direct Debit
- closes #134 ZUGFeRD2PullProvider uses NetPrice for GrossPrice
- support intra community supply (=vat category codes)
- Support different Date formats #136
- corrected RDF metadata for ZF2
- default conformance level now EN16931, not extended
1.7.4
=====
2019-08-24
@@ -163,4 +221,4 @@ ZUGFeRD 1.0
1.0.0
=====
2014-05-22
ZUGFeRD 1.0RC Comfort
ZUGFeRD 1.0RC Comfort

208
Mustang-CLI/pom.xml Normal file
View File

@@ -0,0 +1,208 @@
<?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>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.zugferd</groupId>
<artifactId>Mustang-CLI</artifactId>
<name>Mustang commandline tool</name>
<packaging>jar</packaging>
<version>2.0.0-SNAPSHOT</version>
<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>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>validator</artifactId>
<version>2.0.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>
<dependency>
<!-- for commandline options -->
<groupId>com.sanityinc</groupId>
<artifactId>jargs</artifactId>
<version>2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.riversun</groupId>
<artifactId>bigdoc</artifactId>
<version>0.3.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- for directory validation: -->
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<version>2.6.3</version>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-assertj</artifactId>
<version>2.6.3</version>
</dependency>
<!-- /directory validation: -->
</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>
<!-- allow getImplementationVersion for the pom.xml -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<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>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<!-- /ZUV -->
<!-- generate XSLT files from schematron upon build (goal convert is part
of the preparation of the "package" step)
<plugin> <groupId>com.helger.maven</groupId> <artifactId>ph-sch2xslt-maven-plugin</artifactId>
<version>5.0.8</version> <configuration> <schematronDirectory>${basedir}/src/main/resources/</schematronDirectory>
<xsltDirectory>${basedir}/src/main/resources/xslt</xsltDirectory> </configuration>
<executions> <execution> <goals> <goal>convert</goal> </goals> </execution>
</executions> </plugin> -->
<plugin>
<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>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>
<filter>
<artifact>com.sun.xml.bind:jaxb-core</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>
<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

@@ -16,7 +16,7 @@
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.toecount;
package org.mustangproject.commandline;
import java.math.BigDecimal;

View File

@@ -16,7 +16,7 @@
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.toecount;
package org.mustangproject.commandline;
import java.io.IOException;
import java.nio.file.FileVisitResult;

View File

@@ -16,7 +16,7 @@
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.toecount;
package org.mustangproject.commandline;
import java.io.BufferedReader;
import java.io.File;
@@ -34,7 +34,7 @@ import org.mustangproject.ZUGFeRD.ZUGFeRDConformanceLevel;
import org.mustangproject.ZUGFeRD.ZUGFeRDExporter;
import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1Factory;
import org.mustangproject.ZUGFeRD.ZUGFeRDImporter;
import org.mustangproject.ZUGFeRD.ZUGFeRDMigrator;
import org.mustangproject.validator.ZUGFeRDValidator;
/***
* This is the command line interface to mustangproject
@@ -44,33 +44,29 @@ import org.mustangproject.ZUGFeRD.ZUGFeRDMigrator;
import com.sanityinc.jargs.CmdLineParser;
import com.sanityinc.jargs.CmdLineParser.Option;
public class Toecount {
public class Main {
// build with: /opt/local/bin/mvn clean compile assembly:single
private static void printUsage() {
System.err.println(getUsage());
}
private static String getUsage() {
return "Usage: [-d,--directory] [-l,--listfromstdin] [-i,--ignorefileextension] | [-c,--combine] | [-e,--extract] | [-u,--upgrade] | [-a,--a3only] | [-h,--help] \r\n"
+ "* Count operations\n" + " -d, --directory count ZUGFeRD files in directory to be scanned\n"
return "Usage: --action metrics|combine|extract|a3only|validate [-d,--directory] [-l,--listfromstdin] [-i,--ignore fileextension, PDF/A errors] | [-h,--help] \r\n"
+ "* merics\n" + " -d, --directory count ZUGFeRD files in directory to be scanned\n"
+ " 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)\n"
+ "\n" + "* Merge operations\n" + " -e, --extract extract ZUGFeRD PDF to XML file\n"
+ " [-i, --ignorefileextension] Check for all files (*.*) instead of PDF files only (*.pdf) in metrics, ignore PDF/A input file errors in combine\n"
+ "\n" + "* Merge actions\n" + " extract extract ZUGFeRD PDF to XML file\n"
+ " 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"
+ " -u, --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"
+ " -a, --a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n"
+ " a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n"
+ " [--out <filename>]: set output PDF file\n"
+ " -c, --combine combine XML and PDF file to ZUGFeRD PDF file\n"
+ " combine combine XML and PDF file to ZUGFeRD PDF file\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n"
+ " [--source-xml <filename>]: set input XML file\n"
@@ -79,7 +75,11 @@ public class Toecount {
+ " [--version <1|2>]: set ZUGFeRD version\n"
+ " [--profile <...>]: set ZUGFeRD profile\n"
+ " For ZUGFeRD v1: <B>ASIC, <C>OMFORT or <E>XTENDED\n"
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, E<X>TENDED ";
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, E<X>TENDED "
+ " validate validate XML or PDF file \n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: input PDF or XML file\n"
;
}
private static void printHelp() {
@@ -112,7 +112,7 @@ public class Toecount {
+ "\t\t[--format <fx|zf>]: enable factur-x or ZUGFeRD\r\n"
+ "\t\t[--version <1|2>]: set ZUGFeRD version\r\n" + "\t\t[--profile <...>]: set ZUGFeRD profile\r\n"
+ "\t\t\tFor ZUGFeRD v1: <B>ASIC, <C>OMFORT or <E>XTENDED\r\n"
+ "\t\t\tFor ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, E<X>TENDED\r\n");
+ "\t\t\tFor ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, EX<T>ENDED, <X>Rechnung\r\n");
}
/**
@@ -148,7 +148,7 @@ public class Toecount {
try {
input = buffer.readLine();
} catch (IOException e) {
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
}
@@ -185,7 +185,7 @@ public class Toecount {
try {
selectedName = buffer.readLine();
} catch (IOException e) {
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
}
@@ -202,7 +202,7 @@ public class Toecount {
try {
selectedAnswer = buffer.readLine();
} catch (IOException e) {
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
}
if (!selectedAnswer.equals("Y") && !selectedAnswer.equals("y")) {
System.err.println("Aborted by user");
@@ -253,23 +253,6 @@ public class Toecount {
// --out: output file
Option<String> outOption = parser.addStringOption("out");
// Command: Extract XML
// --extract
// (--source: input PDF file)
// (--out: output XML file)
Option<Boolean> extractOption = parser.addBooleanOption('e', "extract");
// Command: Migrating ZUGFeRD 1 to 2
// --upgrade
// (--source: input XML ZUGFeRD 1 file)
// (--out: output XML ZUGFeRD 2 file)
Option<Boolean> upgradeOption = parser.addBooleanOption('u', "upgrade");
// Command: Convert PDF/A-1 to PDF/A-3
// --a3only
// (--source: input PDF file)
// (--out: output PDF file)
Option<Boolean> a3onlyOption = parser.addBooleanOption('a', "a3only");
// Command: Combining PDF and XML
// --combine
@@ -278,7 +261,6 @@ public class Toecount {
// (--out: output PDF file)
// (--version: ZUGFeRD version)
// (--profile: ZUGFeRD profile)
Option<Boolean> combineOption = parser.addBooleanOption('c', "combine");
Option<String> sourceXmlOption = parser.addStringOption("source-xml");
Option<String> formatOption = parser.addStringOption('f', "format");
Option<String> zugferdVersionOption = parser.addStringOption("version");
@@ -306,31 +288,43 @@ public class Toecount {
String action = parser.getOptionValue(actionOption);
String directoryName = parser.getOptionValue(dirnameOption);
Boolean filesFromStdIn = parser.getOptionValue(filesFromStdInOption, Boolean.FALSE);
Boolean combineRequested = parser.getOptionValue(combineOption, Boolean.FALSE) || ((action!=null)&&(action.equals("combine")));
Boolean extractRequested = parser.getOptionValue(extractOption, Boolean.FALSE) || ((action!=null)&&(action.equals("extract")));
Boolean helpRequested = parser.getOptionValue(helpOption, Boolean.FALSE) || ((action!=null)&&(action.equals("help")));
Boolean upgradeRequested = parser.getOptionValue(upgradeOption, Boolean.FALSE) || ((action!=null)&&(action.equals("upgrade")));
Boolean ignoreFileExt = parser.getOptionValue(ignoreFileExtOption, Boolean.FALSE);
Boolean a3only = parser.getOptionValue(a3onlyOption, Boolean.FALSE) || ((action!=null)&&(action.equals("a3")));
String sourceName = parser.getOptionValue(sourceOption);
String sourceXMLName = parser.getOptionValue(sourceXmlOption);
String outName = parser.getOptionValue(outOption);
String format = parser.getOptionValue(formatOption);
String zugferdVersion = parser.getOptionValue(zugferdVersionOption);
String zugferdProfile = parser.getOptionValue(zugferdProfileOption);
boolean optionsRecognized=false;
if (helpRequested) {
printHelp();
} else if (((directoryName != null) && (directoryName.length() > 0)) || filesFromStdIn.booleanValue()) {
optionsRecognized=true;
} else if ((action!=null)&&(action.equals("metrics"))) {
performMetrics(directoryName, filesFromStdIn, ignoreFileExt);
} else if (combineRequested) {
performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile);
} else if (extractRequested) {
optionsRecognized=true;
} else if ((action!=null)&&(action.equals("combine"))) {
performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile, ignoreFileExt);
optionsRecognized=true;
} else if ((action!=null)&&(action.equals("extract"))) {
performExtract(sourceName, outName);
} else if (a3only) {
optionsRecognized=true;
} else if ((action!=null)&&(action.equals("a3only"))) {
performConvert(sourceName, outName);
} else if (upgradeRequested) {
performUpgrade(sourceName, outName);
optionsRecognized=true;
} else if ((action!=null)&&(action.equals("validate"))) {
optionsRecognized=performValidate(sourceName);
} else if ((action!=null)&&(action.equals("validateExpectValid"))) {
optionsRecognized=performValidateExpect(true, directoryName);
} else if ((action!=null)&&(action.equals("validateExpectInvalid"))) {
optionsRecognized=performValidateExpect(false, directoryName);
} else {
// no argument or argument unknown
printUsage();
@@ -338,42 +332,49 @@ public class Toecount {
}
} catch (Exception e) {
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
System.exit(-1);
}
}
private static void performUpgrade(String xmlName, String outName) throws IOException, TransformerException {
// Get params from user if not already defined
if (xmlName == null) {
xmlName = getFilenameFromUser("ZUGFeRD 1.0 XML source", "ZUGFeRD-invoice.xml", "xml", true, false);
private static boolean performValidate(String sourceName) {
boolean optionsRecognized;
if (sourceName == null) {
sourceName = getFilenameFromUser("Source PDF", "invoice.pdf", "pdf", true, false);
} else {
System.out.println("ZUGFeRD 1.0 XML source set to " + xmlName);
}
if (outName == null) {
outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "zugferd-invoice.xml", "xml", false, true);
} else {
System.out.println("ZUGFeRD 1.0 XML source set to " + outName);
System.out.println("Source PDF set to " + sourceName);
}
// Verify params
ensureFileExists(xmlName);
ensureFileNotExists(outName);
// All params are good! continue...
ZUGFeRDMigrator zmi = new ZUGFeRDMigrator();
String xml = null;
xml = zmi.migrateFromV1ToV2(xmlName);
Files.write(Paths.get(outName), xml.getBytes());
System.out.println("Written to " + outName);
/*
* } catch (FileNotFoundException ex) {
* Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, ex);
*/
ZUGFeRDValidator zfv=new ZUGFeRDValidator();
System.out.println(zfv.validate(sourceName));
optionsRecognized = !zfv.hasOptionsError();
if (!zfv.wasCompletelyValid()) {
System.exit(-1);
}
return optionsRecognized;
}
private static boolean performValidateExpect(boolean valid, String dirName) {
ValidatorFileWalker zfWalk = new ValidatorFileWalker(valid);
Path startingDir = Paths.get(dirName);
try {
Files.walkFileTree(startingDir, zfWalk);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String totalResult="valid";
if (!zfWalk.getResult()) {
totalResult="invalid";
}
System.out.println("Overall test result: "+totalResult);
return true;
}
private static void performConvert(String pdfName, String outName) throws IOException {
/*
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
@@ -433,7 +434,7 @@ public class Toecount {
}
private static void performCombine(String pdfName, String xmlName, String outName, String format, String zfVersion,
String zfProfile) throws Exception {
String zfProfile, Boolean ignoreInputErrors) throws Exception {
/*
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
* .setProducer("toecount") .setCreator(System.getProperty("user.name"))
@@ -458,14 +459,14 @@ public class Toecount {
if (outName == null) {
outName = getFilenameFromUser("Ouput PDF", "invoice.ZUGFeRD.pdf", "pdf", false, true);
} else {
System.out.println("Ouput PDF set to " + outName);
System.out.println("Output PDF set to " + outName);
}
if (format == null) {
try {
format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD,)", "zf", "fx|zf");
format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD)", "zf", "fx|zf");
} catch (Exception e) {
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
}
} else {
System.out.println("Format set to " + format);
@@ -473,9 +474,9 @@ public class Toecount {
if (zfVersion == null) {
try {
zfVersion = getStringFromUser("Version (1 or 2)", "1", "1|2");
zfVersion = getStringFromUser("Version (1 or 2)", Integer.toString(ZUGFeRDExporter.DefaultZUGFeRDVersion), "1|2");
} catch (Exception e) {
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
}
} else {
System.out.println("Version set to " + zfVersion);
@@ -488,11 +489,11 @@ public class Toecount {
zfProfile = getStringFromUser("Profile b)asic, c)omfort or e)xtended", "e", "B|b|C|c|E|e");
} else {
zfProfile = getStringFromUser(
"Profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, E[X]TENDED", "E",
"M|m|W|w|B|b|C|c|E|e|X|x|");
"Profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, EX[T]ENDED or [X]RECHNUNG", "E",
"M|m|W|w|B|b|C|c|E|e|T|t|X|x|");
}
} catch (Exception e) {
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
}
} else {
@@ -530,8 +531,10 @@ public class Toecount {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.CIUS;
} else if (zfProfile.equals("e")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EN16931;
} else if (zfProfile.equals("x")) {
} else if (zfProfile.equals("t")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED;
} else if (zfProfile.equals("x")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.XRECHNUNG;
} else {
throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile));
}
@@ -540,10 +543,14 @@ public class Toecount {
}
// All params are good! continue...
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setProducer("Toecount")
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setProducer("Mustang-cli")
.setZUGFeRDVersion(zfIntVersion)
.setCreator(System.getProperty("user.name")).setZUGFeRDConformanceLevel(zfConformanceLevelProfile)
.load(pdfName);
if (ignoreInputErrors) {
ze.ignoreA1Errors();
}
if (format.equals("fx")) {
ze.setFacturX();
@@ -556,7 +563,7 @@ public class Toecount {
System.out.println("Written to " + outName);
} catch (IOException e) {
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e);
}
}

View File

@@ -16,7 +16,7 @@
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.toecount;
package org.mustangproject.commandline;
import java.math.BigDecimal;

View File

@@ -0,0 +1,95 @@
package org.mustangproject.commandline;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.DateFormat;
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;
public class ValidatorFileWalker
extends SimpleFileVisitor<Path> {
private static final Logger LOGGER = LoggerFactory.getLogger(ValidatorFileWalker.class.getCanonicalName()); // log
protected PathMatcher matcher;
protected ZUGFeRDValidator zul;
protected int fileCount=1;
protected boolean expectValid=true;
protected boolean allValid=true;
public ValidatorFileWalker(boolean expectValid) {
this.zul = new ZUGFeRDValidator();
this.expectValid=expectValid;
matcher = FileSystems.getDefault().getPathMatcher("glob:*.{pdf,xml}");
}
public boolean getResult() {
return allValid;
}
// Print information about
// each type of file.
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attr) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//get current date time with Date()
Date date = new Date();
String expectedString="valid";
if (!expectValid) {
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));
}
}
return FileVisitResult.CONTINUE;
}
// Print each directory visited.
@Override
public FileVisitResult postVisitDirectory(Path dir,
IOException exc) {
LOGGER.info("\nDirectory: %s%n", dir);
return FileVisitResult.CONTINUE;
}
// If there is some error accessing
// the file, let the user know.
// If you don't override this method
// and an error occurs, an IOException
// is thrown.
@Override
public FileVisitResult visitFileFailed(Path file,
IOException exc) {
LOGGER.error(exc.getMessage(),exc);
return FileVisitResult.CONTINUE;
}
}

View File

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

6
NOTICE
View File

@@ -22,4 +22,8 @@ Copyright (c) 2002-2007, www.pdfbox.org
Copyright (c) 2006-2007, www.jempbox.org
Apache PDFBox was based on source code originally developed in the PaDaF project.
Copyright (c) 2010 Atos Worldline SAS
Copyright (c) 2010 Atos Worldline SAS
Based on VeraPDF-library https://github.com/veraPDF/veraPDF-library licensed under the MPL 2.0
Based on PH-Schematron https://github.com/phax/ph-schematron licensed under the APL2.0
Based on https://github.com/itplr-kosit/xrechnung-schematron licensed under the APL2.0

View File

@@ -1,14 +0,0 @@
Apache PDFBox
Copyright 2014 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
Based on source code originally developed in the PDFBox, JempBox and
FontBox projects.
Copyright (c) 2002-2007, www.pdfbox.org
Copyright (c) 2006-2007, www.jempbox.org
Based on source code originally developed in the PaDaF project.
Copyright (c) 2010 Atos Worldline SAS

View File

@@ -37,7 +37,6 @@ As dependency use this
<dependency>
<groupId>org.mustangproject.ZUGFeRD</groupId>
<artifactId>mustang</artifactId>
<version>1.7.4</version>
</dependency>
```

View File

@@ -1,218 +1,41 @@
package mustang15test;
package mustangtest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTransaction;
import org.mustangproject.ZUGFeRD.ZUGFeRD2PullProvider;
import org.mustangproject.ZUGFeRD.ZUGFeRDExporter;
import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1Factory;
public class MustangWriter implements IZUGFeRDExportableTransaction {
public static void main(String[] args) {
MustangWriter m1 = new MustangWriter();
m1.apply();
}
private void apply() {
try {
System.out.println("Reading Blanko-PDF");
ZUGFeRDExporter ze =
new ZUGFeRDExporterFromA1Factory().setProducer("My Application").setCreator(System.getProperty("user.name")).load("./MustangGnuaccountingBeispielRE-20171118_506blanko.pdf");
System.out.println("Generating and attaching ZUGFeRD-Data");
ze.PDFattachZugferdFile(this);
System.out.println("Writing ZUGFeRD-PDF");
ze.export("./MustangGnuaccountingBeispielRE-20171118_506new.pdf");
System.out.println("Done.");
} catch (IOException e) {
Logger.getLogger(MustangWriter.class.getName()).log(Level.SEVERE, null, e1);
}
}
@Override
public String getCurrency() {
// TODO Auto-generated method stub
return null;
}
@Override
public Date getDeliveryDate() {
return new GregorianCalendar(2017, Calendar.NOVEMBER, 17).getTime();
}
@Override
public Date getDueDate() {
return new GregorianCalendar(2017, Calendar.DECEMBER, 9).getTime();
}
@Override
public Date getIssueDate() {
return new GregorianCalendar(2017, Calendar.NOVEMBER, 18).getTime();
}
@Override
public String getNumber() {
return "RE-20171118/506";
}
@Override
public String getOwnBIC() {
return "COBADEFFXXX";
}
@Override
public String getOwnBankName() {
return "Commerzbank";
}
@Override
public String getOwnCountry() {
return "DE";
}
@Override
public String getOwnIBAN() {
return "DE88 2008 0000 0970 3757 00";
}
@Override
public String getOwnLocation() {
return "Stadthausen";
}
@Override
public String getOwnOrganisationFullPlaintextInfo() {
return "Bei Spiel GmbH\n" +
"Ecke 12\n" +
"12345 Stadthausen\n" +
"Geschäftsführer: Max Mustermann";
}
@Override
public String getOwnOrganisationName() {
return "Bei Spiel GmbH";
}
@Override
public String getOwnPaymentInfoText() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getOwnStreet() {
return "Ecke 12";
}
@Override
public String getOwnTaxID() {
return "22/815/0815/4";
}
@Override
public String getOwnVATID() {
return "DE136695976";
}
@Override
public String getOwnZIP() {
return "12345";
}
@Override
public String getPaymentTermDescription() {
// TODO Auto-generated method stub
return null;
}
@Override
public IZUGFeRDExportableContact getRecipient() {
return new Contact();
}
@Override
public String getReferenceNumber() {
// TODO Auto-generated method stub
return null;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFAllowances() {
// TODO Auto-generated method stub
return null;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFCharges() {
// TODO Auto-generated method stub
return null;
}
@Override
public IZUGFeRDExportableItem[] getZFItems() {
Item[] allItems = new Item[3];
Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR", new BigDecimal("7.000000"));
Product balloonProduct = new Product("", "Luftballon: Bunt, ca. 500ml", "C62", new BigDecimal("19.000000"));
Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000"));
allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct);
allItems[2] = new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct);
return allItems;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
// TODO Auto-generated method stub
return null;
}
}
class Contact implements IZUGFeRDExportableContact {
@Override
public String getCountry() {
return "DE";
}
@Override
public String getLocation() {
return "Spielkreis";
}
@Override
public String getName() {
return "Theodor Est";
}
@Override
public String getStreet() {
return "Bahnstr. 42";
}
@Override
public String getVATID() {
return "DE999999999";
}
@Override
public String getZIP() {
return "88802";
}
@@ -253,13 +76,11 @@ class Item implements IZUGFeRDExportableItem {
this.product = product;
}
@Override
public IZUGFeRDAllowanceCharge[] getItemAllowances() {
// TODO Auto-generated method stub
return null;
}
@Override
public IZUGFeRDAllowanceCharge[] getItemCharges() {
// TODO Auto-generated method stub
return null;
@@ -310,3 +131,147 @@ class Product implements IZUGFeRDExportableProduct {
VATPercent = vATPercent;
}
}
public class MustangWriter implements IZUGFeRDExportableTransaction {
private void apply() {
try {
System.out.println("Reading Blanko-PDF");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setProducer("My Application")
.setCreator(System.getProperty("user.name"))
.load("./MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
System.out.println("Generating and attaching ZUGFeRD-Data");
ze.PDFattachZugferdFile(this);
System.out.println("Writing ZUGFeRD-PDF");
ze.export("./MustangGnuaccountingBeispielRE-20170509_505new.pdf");
System.out.println("Done.");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
MustangWriter mw=new MustangWriter();
mw.apply();
}
public String getCurrency() {
return "EUR";
}
public Date getDeliveryDate() {
return new GregorianCalendar(2017, Calendar.NOVEMBER, 17).getTime();
}
public Date getDueDate() {
return new GregorianCalendar(2017, Calendar.DECEMBER, 9).getTime();
}
public Date getIssueDate() {
return new GregorianCalendar(2017, Calendar.NOVEMBER, 18).getTime();
}
public String getNumber() {
// TODO Auto-generated method stub
return "RE-20171118/506";
}
public String getOwnBIC() {
// TODO Auto-generated method stub
return "COBADEFFXXX";
}
public String getOwnBankName() {
// TODO Auto-generated method stub
return "Commerzbank";
}
public String getOwnCountry() {
// TODO Auto-generated method stub
return "DE";
}
public String getOwnIBAN() {
// TODO Auto-generated method stub
return "DE88 2008 0000 0970 3757 00";
}
public String getOwnLocation() {
// TODO Auto-generated method stub
return "Stadthausen";
}
public String getOwnOrganisationFullPlaintextInfo() {
// TODO Auto-generated method stub
return "Bei Spiel GmbH\n" + "Ecke 12\n" + "12345 Stadthausen\n" + "Geschäftsführer: Max Mustermann";
}
public String getOwnOrganisationName() {
// TODO Auto-generated method stub
return "Bei Spiel GmbH";
}
public String getOwnPaymentInfoText() {
// TODO Auto-generated method stub
return null;
}
public String getOwnStreet() {
return "Ecke 12";
}
public String getOwnTaxID() {
return "22/815/0815/4";
}
public String getOwnVATID() {
return "DE136695976";
}
public String getOwnZIP() {
return "12345";
}
public String getPaymentTermDescription() {
// TODO Auto-generated method stub
return null;
}
public IZUGFeRDExportableContact getRecipient() {
return new Contact();
}
public String getReferenceNumber() {
// TODO Auto-generated method stub
return null;
}
public IZUGFeRDAllowanceCharge[] getZFAllowances() {
// TODO Auto-generated method stub
return null;
}
public IZUGFeRDAllowanceCharge[] getZFCharges() {
// TODO Auto-generated method stub
return null;
}
public IZUGFeRDExportableItem[] getZFItems() {
Item[] allItems = new Item[3];
Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR",
new BigDecimal("7.000000"));
Product balloonProduct = new Product("", "Luftballon: Bunt, ca. 500ml", "C62", new BigDecimal("19.000000"));
Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000"));
allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct);
allItems[2] = new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct);
return allItems;
}
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
// TODO Auto-generated method stub
return null;
}
}

993
doc/ZUV-Architektur.graphml Normal file
View File

@@ -0,0 +1,993 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.17-->
<key attr.name="Beschreibung" attr.type="string" for="graph" id="d0"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
<key for="port" id="d3" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d4"/>
<key attr.name="description" attr.type="string" for="node" id="d5"/>
<key for="node" id="d6" yfiles.type="nodegraphics"/>
<key for="graphml" id="d7" yfiles.type="resources"/>
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<data key="d0"/>
<node id="n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="137.0" x="120.375" y="0.0"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.83984375" x="38.580078125" y="17.93359375">PDF+XML<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n1" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="264.666015625" width="366.0" x="1950.0" y="190.666015625"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="366.0" x="0.0" y="0.0">ZUGFeRD</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 2</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n1:">
<node id="n1::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="1966.0" y="227.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="100.73828125" x="25.630859375" y="17.93359375">Schematron files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n1::n1">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="2148.0" y="386.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="76.521484375" x="37.7392578125" y="17.93359375">Schema files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n1::n2">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="1966.0" y="386.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="85.615234375" x="33.1923828125" y="17.93359375">Codelist XMLs<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<node id="n2" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="95.666015625" width="408.0" x="1512.0" y="195.666015625"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="408.0" x="0.0" y="0.0">EN16931</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 3</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n2:">
<node id="n2::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="1731.0" y="232.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="110.453125" x="31.2734375" y="12.93359375">CEF Codelist Excel<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n2::n1">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="1528.0" y="232.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="100.2578125" x="36.37109375" y="12.93359375">CEN Schematron<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<node id="n3" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="95.666015625" width="205.0" x="2346.0" y="195.666015625"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="205.0" x="0.0" y="0.0">UN/CEFACT</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 4</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n3:">
<node id="n3::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="2362.0" y="232.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="76.521484375" x="48.2392578125" y="12.93359375">Schema files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<node id="n4">
<data key="d6">
<y:GenericNode configuration="BevelNode">
<y:Geometry height="54.0" width="163.75" x="474.625" y="641.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="70.638671875" x="46.5556640625" y="17.93359375">XML Report<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="493.33203125" width="1268.0" x="0.0" y="85.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="1268.0" x="0.0" y="0.0">ZUV</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 5</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n5:">
<node id="n5::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="673.0" y="519.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="95.18359375" x="38.908203125" y="12.93359375">PH-Schematron<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n1">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="84.0" x="801.25" y="386.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="28.24609375" x="27.876953125" y="17.93359375">XML<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n2">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="84.0" x="108.5" y="386.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="57.431640625" x="13.2841796875" y="17.93359375">Metadata<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n3">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="64.0" y="519.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="94.66796875" x="39.166015625" y="12.93359375">Metadata check<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n4">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="619.25" y="386.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.91015625" x="46.044921875" y="17.93359375">XSLT files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n5">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="1100.0" y="386.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.91015625" x="46.044921875" y="17.93359375">XSLT files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n6">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="84.0" x="311.5" y="386.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="92.81640625" x="-4.408203125" y="17.93359375">Additional data<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n7">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="267.0" y="519.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="130.052734375" x="21.4736328125" y="12.93359375">Additional data check<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n8">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="876.0" y="519.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="95.18359375" x="38.908203125" y="12.93359375">PH-Schematron<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n9" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="169.666015625" width="205.0" x="251.0" y="121.666015625"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="205.0" x="0.0" y="0.0">Mustangproject</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 1</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n5::n9:">
<node id="n5::n9::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="267.0" y="232.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="47.6875" x="62.65625" y="12.93359375">PDFBox<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n9::n1">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="267.0" y="158.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="53.9453125" x="59.52734375" y="12.93359375">Mustang<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<node id="n5::n10" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="95.666015625" width="205.0" x="16.0" y="121.666015625"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="205.0" x="0.0" y="0.0">VeraPDF</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 6</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n5::n10:">
<node id="n5::n10::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="32.0" y="158.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="52.123046875" x="60.4384765625" y="12.93359375">VeraPDF<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<node id="n5::n11">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="1079.0" y="519.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="85.80859375" x="43.595703125" y="12.93359375">Schema check<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n12">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="437.25" y="386.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.91015625" x="46.044921875" y="17.93359375">XSLT files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n13">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="470.0" y="519.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="95.18359375" x="38.908203125" y="12.93359375">PH-Schematron<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<node id="n6" yfiles.foldertype="group">
<data key="d4"/>
<data key="d5"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="105.666015625" width="184.0" x="1298.0" y="190.666015625"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="184.0" x="0.0" y="0.0">XRechnung</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 7</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n6:">
<node id="n6::n0">
<data key="d5"/>
<data key="d6">
<y:GenericNode configuration="BevelNode2">
<y:Geometry height="54.0" width="152.0" x="1314.0" y="227.33203125"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="72.7890625" x="39.60546875" y="17.93359375">Schematron<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<edge id="e0" source="n2::n0" target="n1::n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="0.0" ty="-27.0">
<y:Point x="1817.5" y="370.83203125"/>
<y:Point x="2042.0" y="370.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n3::n0" target="n1::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="0.0" ty="-27.0">
<y:Point x="2448.5" y="306.83203125"/>
<y:Point x="2224.0" y="306.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e0" source="n5::n1" target="n5::n8">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="10.5" sy="27.0" tx="-57.66666666666667" ty="-22.0">
<y:Point x="853.75" y="487.83203125"/>
<y:Point x="904.8333333333334" y="487.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e1" source="n5::n1" target="n5::n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-10.5" sy="27.0" tx="43.25" ty="-22.0">
<y:Point x="832.75" y="487.83203125"/>
<y:Point x="802.75" y="487.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e2" source="n5::n2" target="n5::n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="0.0" ty="-22.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e3" source="n5::n4" target="n5::n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="-43.25" ty="-22.0">
<y:Point x="695.25" y="455.83203125"/>
<y:Point x="716.25" y="455.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e4" source="n5::n5" target="n5::n8">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="0.0" ty="-22.0">
<y:Point x="1176.0" y="455.83203125"/>
<y:Point x="962.5" y="455.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e5" source="n5::n6" target="n5::n7">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="0.0" ty="-22.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e6" source="n5::n9::n0" target="n5::n6">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="0.0" ty="-27.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e7" source="n5::n9::n0" target="n5::n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-57.666666666666686" sy="22.0" tx="0.0" ty="-27.0">
<y:Point x="295.8333333333333" y="306.83203125"/>
<y:Point x="150.5" y="306.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e8" source="n5::n9::n0" target="n5::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="57.66666666666667" sy="22.0" tx="0.0" ty="-27.0">
<y:Point x="411.1666666666667" y="306.83203125"/>
<y:Point x="843.25" y="306.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::n9::e0" source="n5::n9::n1" target="n5::n9::n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="0.0" ty="-22.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n0" target="n5::n10::n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-34.25" sy="27.0" tx="0.0" ty="-22.0">
<y:Point x="154.625" y="69.5"/>
<y:Point x="118.5" y="69.5"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n5::n10::n0" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="-70.17857142857144" ty="-27.0">
<y:Point x="118.5" y="232.83203125"/>
<y:Point x="48.5" y="232.83203125"/>
<y:Point x="48.5" y="625.83203125"/>
<y:Point x="486.32142857142856" y="625.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n0" target="n5::n9">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="34.25" sy="27.0" tx="-94.25" ty="-84.8330078125">
<y:Point x="223.125" y="69.5"/>
<y:Point x="259.25" y="69.5"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e5" source="n5::n0" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="23.39285714285714" ty="-27.0">
<y:Point x="759.5" y="593.83203125"/>
<y:Point x="579.8928571428571" y="593.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e6" source="n5::n7" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="-23.39285714285714" ty="-27.0">
<y:Point x="353.5" y="593.83203125"/>
<y:Point x="533.1071428571429" y="593.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e7" source="n5::n3" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="-46.785714285714285" ty="-27.0">
<y:Point x="150.5" y="609.83203125"/>
<y:Point x="509.7142857142857" y="609.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e8" source="n5::n8" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="46.78571428571428" ty="-27.0">
<y:Point x="962.5" y="609.83203125"/>
<y:Point x="603.2857142857142" y="609.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e9" source="n2::n1" target="n5::n5">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="0.0" ty="-27.0">
<y:Point x="1614.5" y="338.83203125"/>
<y:Point x="1176.0" y="338.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e10" source="n1::n0" target="n5::n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="0.0" ty="-27.0">
<y:Point x="2042.0" y="354.83203125"/>
<y:Point x="695.25" y="354.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e9" source="n5::n1" target="n5::n11">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="31.5" sy="27.0" tx="-43.25" ty="-22.0">
<y:Point x="874.75" y="471.83203125"/>
<y:Point x="1122.25" y="471.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e11" source="n5::n11" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="70.17857142857142" ty="-27.0">
<y:Point x="1165.5" y="625.83203125"/>
<y:Point x="626.6785714285714" y="625.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e12" source="n1::n1" target="n5::n11">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="43.25" ty="-22.0">
<y:Point x="2224.0" y="503.83203125"/>
<y:Point x="1208.75" y="503.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e13" source="n1::n2" target="n5::n8">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="57.666666666666686" ty="-22.0">
<y:Point x="2042.0" y="487.83203125"/>
<y:Point x="1020.1666666666667" y="487.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e14" source="n6::n0" target="n5::n12">
<data key="d8"/>
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="0.0" ty="-27.0">
<y:Point x="1390.0" y="322.83203125"/>
<y:Point x="513.25" y="322.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e10" source="n5::n12" target="n5::n13">
<data key="d8"/>
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="-43.25" ty="-22.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e11" source="n5::n1" target="n5::n13">
<data key="d8"/>
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-31.5" sy="27.0" tx="43.25" ty="-22.0">
<y:Point x="811.75" y="471.83203125"/>
<y:Point x="599.75" y="471.83203125"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e15" source="n5::n13" target="n4">
<data key="d8"/>
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="0.0" ty="-27.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d7">
<y:Resources/>
</data>
</graphml>

1117
doc/ZUV-Architektur.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 154 KiB

View File

@@ -1,23 +1,44 @@
## General approach
1. build
as excercise to check if the neccessary tools are there, the build is in a stable state and works on your platform, e.g. download and extract https://github.com/ZUGFeRD/mustangproject/archive/master.zip and run ./mvnw clean package
Mvnw is a maven wrapper which will download maven.Maven is the dependency management tool which will download all libraries, their dependencies, and build the whole thing.
You will need a Java JDK, e.g. https://www.azul.com/downloads/zulu-community/?architecture=x86-64-bit&package=jdk
If that does not work feel free to address the community support mailing list with error messages/steps to reproduce.
You may already start developing what you wanted. Of course you can use any editor or IDE you like, I suggest Intellij Community Edition https://www.jetbrains.com/de-de/idea/download/
2. fork
Once you can build, the idea is that you contribute patches via pull requests. For this you need a github account and a personal copy of the repository to store your changes in. Just klick fork on the mustangproject. On your copy you will have git write access. My suggestion as git client is sourcetree (I can send you instructions how to set it up).
3. branch
If you do a pull request, please do a feature branch, e.g. if you are working on a feature abc you could call your branch feature_abc. Merge requests unfortunately don't work if you don't have a branch you request merge of. Technically we follow the "github flow" strategy (not to be exchanged with the more sophisticated "git flow" strategy)
4. test
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
## New build
Target platform is java 1.7
Target platform is java 1.8
## Build
Toecount is now part of the package which can be build with
The package can be build with
```
mvn clean package
mvnw clean package
```
## Eclipse
Eclipse XPath Evaluation plugin from the Eclipse Marketplace provides a very handy view to apply XPath on a XML file, useful e.g. when you try XPath expressions or you only have the Xpath, not the line number, to a problem.
To be able to validate against schema files, enter Settings|XML|XML Catalog and add the location of e.g.
zugferd2p0_en16931.xsd, which will resolve to the key (namespace)
urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100, just as ZUGFeRD1p0.xsd will provide the key for
urn:ferd:CrossIndustryDocument:invoice:1p0
## Test
`package -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8001 -Xnoagent -Djava.compiler=NONE"`
@@ -72,6 +93,14 @@ Sign in in GitHub and click on the profile picture -> Settings. Now just generat
![screenshot](development_documentation_screenshot_github_settings.png "Screenshot Github Settings")
The Token-ID is the password.
## Integrate before release
If you added functionality which you need to test in another project before a new version of Mustang is released you can
install the jar you just generated in your target branch in your local maven cache so it gets picked *instead* of the
maybe not yet even existing new release version:
`mvn install:install-file -Dfile=mustang-1.7.6-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.7.6 -Dpackaging=jar -DgeneratePom=true`
## Release
@@ -79,7 +108,8 @@ You will need a git client on the console, if that's available can e.g. be check
Change to the root of the repo.
Change to the project directory and run
* `mvn clean install` . If that works you can
* `mvn clean install` confirm javadoc is OK with
* `mvn javadoc:javadoc`. If that works you can
* clean the release with `mvn release:clean` and prepare the release with
* `mvn release:prepare -DignoreSnapshots=true` and enter the version numbers.
* After that is through you can create a new release via `mvn release:perform -Dmaven.java.skip=True`.This will also update the maven repo.
@@ -103,4 +133,4 @@ Afterwards you can access the release page and update the documentation, e.g. up
* put announcement on usegroup
* email the mailing list
* freshcode.club

295
library/pom.xml Normal file
View File

@@ -0,0 +1,295 @@
<?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>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Library to write and read FacturX and ZUGFeRD e-invoices. </name>
<description>The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs. To write files, a provided PDF/A will be combined with generated or provided XML.
</description>
<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>mustang-2.0.0-SNAPSHOT</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>1.8</maven.compiler.compilerVersion>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE -->
<dependency>
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
<version>9.8.0-11</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>preflight</artifactId>
<version>[2.0.15,2.0.17]</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>[2.0.15,2.0.17]</version>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.helger</groupId>
<artifactId>ph-schematron</artifactId>
<version>5.0.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<version>2.6.2</version>
<scope>test</scope>
</dependency>
<!-- For Toecount -->
<dependency>
<groupId>com.sanityinc</groupId>
<artifactId>jargs</artifactId>
<version>2.0-SNAPSHOT</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>
<!-- toecount -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>org.mustangproject.toecount.Toecount</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>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- /toecount -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<excludePackageNames>org.mustangproject.ZUGFeRD.model.*</excludePackageNames>
</configuration>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<altDeploymentRepository>internal.repo::default::file://${project.build.directory}/mvn-repo
</altDeploymentRepository>
</configuration>
</plugin>
<plugin>
<groupId>com.github.github</groupId>
<artifactId>site-maven-plugin</artifactId>
<version>0.12</version>
<configuration>
<message>Maven artifacts for ${project.version}</message>
<!-- git commit message -->
<noJekyll>true</noJekyll>
<!-- disable webpage processing -->
<outputDirectory>${project.build.directory}/mvn-repo</outputDirectory>
<!-- matches distribution management repository url above -->
<branch>refs/heads/mvn-repo</branch>
<!-- remote branch name -->
<includes>
<include>**/*</include>
</includes>
<merge>true</merge>
<repositoryName>mustangproject</repositoryName>
<!-- github repo name -->
<repositoryOwner>ZUGFeRD</repositoryOwner>
<!-- github username -->
</configuration>
<executions>
<!-- run site-maven-plugin's 'site' target as part of the build's normal
'deploy' phase -->
<execution>
<goals>
<goal>site</goal>
</goals>
<phase>deploy</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.mustangproject.toecount.Toecount</mainClass>
</transformer>
</transformers>
<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>
<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>
<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

@@ -0,0 +1,69 @@
package org.mustangproject;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class XMLTools {
public static String nDigitFormat(BigDecimal value, int scale) {
/*
* I needed 123,45, locale independent.I tried
* NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is locale
* specific.I also tried DecimalFormat df = new DecimalFormat( "0,00" );
* df.setDecimalSeparatorAlwaysShown(true); df.setGroupingUsed(false);
* DecimalFormatSymbols symbols = new DecimalFormatSymbols();
* symbols.setDecimalSeparator(','); symbols.setGroupingSeparator(' ');
* df.setDecimalFormatSymbols(symbols);
*
* but that would not switch off grouping. Although I liked very much the
* (incomplete) "BNF diagram" in
* http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html in the
* end I decided to calculate myself and take eur+sparator+cents
*
*/
return value.setScale(scale, RoundingMode.HALF_UP).toPlainString();
}
public static String encodeXML(CharSequence s) {
StringBuilder sb = new StringBuilder();
int len = s.length();
for (int i=0;i<len;i++) {
int c = s.charAt(i);
if (c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
c = ((c-0xd7c0)<<10) | (s.charAt(++i)&0x3ff); // UTF16 decode
}
if (c < 0x80) { // ASCII range: test most common case first
if (c < 0x20 && (c != '\t' && c != '\r' && c != '\n')) {
// Illegal XML character, even encoded. Skip or substitute
sb.append("&#xfffd;"); // Unicode replacement character
} else {
switch(c) {
case '&': sb.append("&amp;"); break;
case '>': sb.append("&gt;"); break;
case '<': sb.append("&lt;"); break;
// Uncomment next two if encoding for an XML attribute
// case '\'' sb.append("&apos;"); break;
// case '\"' sb.append("&quot;"); break;
// Uncomment next three if you prefer, but not required
// case '\n' sb.append("&#10;"); break;
// case '\r' sb.append("&#13;"); break;
// case '\t' sb.append("&#9;"); break;
default: sb.append((char)c);
}
}
} else if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) {
// Illegal XML character, even encoded. Skip or substitute
sb.append("&#xfffd;"); // Unicode replacement character
} else {
sb.append("&#x");
sb.append(Integer.toHexString(c));
sb.append(';');
}
}
return sb.toString();
}
}

View File

@@ -0,0 +1,85 @@
package org.mustangproject.ZUGFeRD;
public class Contact implements IZUGFeRDExportableContact {
protected String name,phone,email,zip,street,location,country;
public Contact(String name, String phone, String email, String street, String zip, String location, String country) {
this.name = name;
this.phone = phone;
this.email = email;
this.street = street;
this.zip = zip;
this.location = location;
this.country = country;
}
@Override
public String getName() {
return name;
}
public Contact setName(String name) {
this.name = name;
return this;
}
@Override
public String getPhone() {
return phone;
}
public Contact setPhone(String phone) {
this.phone = phone;
return this;
}
public String getEMail() {
return email;
}
public Contact setEMail(String email) {
this.email = email;
return this;
}
public String getZIP() {
return zip;
}
public Contact setZIP(String zip) {
this.zip = zip;
return this;
}
@Override
public String getStreet() {
return street;
}
public Contact setStreet(String street) {
this.street = street;
return this;
}
@Override
public String getLocation() {
return location;
}
public Contact setLocation(String location) {
this.location = location;
return this;
}
@Override
public String getCountry() {
return country;
}
public Contact setCountry(String country) {
this.country = country;
return this;
}
}

View File

@@ -29,8 +29,8 @@ public class CustomXMLProvider implements IXMLProvider, IProfileProvider {
public void setXML(byte[] newData) {
String zf = new String(newData);
if (!zf.contains("<rsm:CrossIndustry")) {
throw new RuntimeException("ZUGFeRD XML does not contain <rsm:CrossIndustry and can thus not be valid");
if (!zf.contains("CrossIndustry")) {
throw new RuntimeException("ZUGFeRD XML does not contain (<rsm:)CrossIndustry and can thus not be valid");
}
zugferdData = newData;

View File

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

View File

@@ -124,4 +124,13 @@ public interface IZUGFeRDExportableContact {
return null;
}
/**
* returns additional address information which is display in xml tag "LineTwo"
*
* @return additional address information
*/
default String getAdditionalAddress() {
return null;
}
}

View File

@@ -47,14 +47,27 @@ public interface IZUGFeRDExportableItem {
BigDecimal getPrice();
/**
* how many
* how many get billed
*
* @return the quantity of the item
*/
BigDecimal getQuantity();
/**
* how many items units per price
*
* @return item units per price
*/
default BigDecimal getBasisQuantity() {
return BigDecimal.ONE.setScale(4);
}
default String getCategoryCode() {
return TaxCategoryCodeTypeConstants.STANDARDRATE;
}
default String getAdditionalReferencedDocumentID() {
return null;
}
}

View File

@@ -0,0 +1,11 @@
package org.mustangproject.ZUGFeRD;
public interface IZUGFeRDExportablePostalTradeAddress {
default String getPostcodeCode(){return null;}
default String getLineOne() {return null;}
default String getLineTwo() {return null;}
default String getLineThree() {return null;}
default String getCityName() {return null;}
default String getCountryID() {return null;}
default String getCountrySubDivisionName() {return null;}
}

View File

@@ -75,11 +75,48 @@ public interface IZUGFeRDExportableProduct {
*/
String getDescription();
/**
* Get the ID that had been assigned by the seller to
* identify the product
*
* @return seller assigned product ID
*/
default String getSellerAssignedID() {
return null;
}
/**
* Get the ID that had been assigned by the buyer to
* identify the product
*
* @return buyer assigned product ID
*/
default String getBuyerAssignedID() {
return null;
}
/**
* VAT percent of the product (e.g. 19, or 5.1 if you like)
*
* @return VAT percent of the product
*/
BigDecimal getVATPercent();
default boolean isIntraCommunitySupply() {
return false;
}
default String getTaxCategoryCode() {
if (isIntraCommunitySupply()) {
return "K";
} else {
return "S";
}
}
default String getTaxExemptionReason() {
if (isIntraCommunitySupply())
return "Intra-community supply";
return null;
}
}

View File

@@ -106,6 +106,16 @@ public interface IZUGFeRDExportableTransaction {
}
/**
* subject of the document e.g. invoice and order
* number as human readable text
*
* @return string with document subject
*/
default String getSubjectNote() {
return null;
}
IZUGFeRDAllowanceCharge[] getZFAllowances();
@@ -128,10 +138,21 @@ public interface IZUGFeRDExportableTransaction {
/**
* the creditors payment informations
*
* @deprecated use getTradeSettlement
* @return an array of IZUGFeRDTradeSettlementPayment
*/
IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment();
@Deprecated
default IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
return null;
}
/**
* the payment information for any payment means
*
* @return an array of IZUGFeRDTradeSettlement
*/
default IZUGFeRDTradeSettlement[] getTradeSettlement() {
return null;
}
/**
@@ -221,6 +242,16 @@ public interface IZUGFeRDExportableTransaction {
*/
Date getDeliveryDate();
/**
* get delivery date in more specific form. If this and getDeliveryDate() are
* specified, this value will be taken
*
* @return instance holding date and format
*/
default IZUGFeRDDate getZFDeliveryDate() {
return null;
}
/**
* get main invoice currency used on the invoice
@@ -241,6 +272,24 @@ public interface IZUGFeRDExportableTransaction {
return null;
}
/**
* get payment terms. if set, getPaymentTermDescription() and getDueDate() are
* ignored
*
* @return
*/
default IZUGFeRDPaymentTerms getPaymentTerms() {
return null;
}
/**
* returns if a rebate agreements exists
*
* @return
*/
default boolean rebateAgreementExists() {
return false;
}
/**
* get reference document number typically used for Invoice Corrections Will be added as IncludedNote in comfort profile
@@ -340,4 +389,14 @@ public interface IZUGFeRDExportableTransaction {
default BigDecimal getTotalPrepaidAmount() {
return BigDecimal.ZERO;
}
/***
* delivery address, i.e. ram:ShipToTradeParty (only supported for zf2)
* @return
*/
default IZUGFeRDExportableContact getDeliveryAddress() {
return null;
}
}

View File

@@ -0,0 +1,15 @@
package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
public interface IZUGFeRDPaymentDiscountTerms {
BigDecimal getCalculationPercentage();
IZUGFeRDDate getBaseDate();
int getBasePeriodMeasure();
String getBasePeriodUnitCode();
}

View File

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

View File

@@ -0,0 +1,40 @@
/** **********************************************************************
*
* Copyright 2019 by ak on 12.04.19.
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
public interface IZUGFeRDTradeSettlement {
/***
*
* @return zf2 xml for applicableHeaderTradeSettlement
*/
String getSettlementXML();
/***
*
* @return zf2 xml for applicableHeaderTradePayment
*/
default String getPaymentXML() {
return null;
}
}

View File

@@ -0,0 +1,57 @@
/** **********************************************************************
*
* Copyright 2019 by ak on 12.04.19.
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import org.mustangproject.XMLTools;
public interface IZUGFeRDTradeSettlementDebit extends IZUGFeRDTradeSettlement {
default String getSettlementXML() {
String xml = " <ram:SpecifiedTradeSettlementPaymentMeans>\n" //$NON-NLS-1$
+ " <ram:TypeCode>59</ram:TypeCode>\n" //$NON-NLS-1$
+ " <ram:PayerPartyDebtorFinancialAccount>\n" //$NON-NLS-1$
+ " <ram:IBANID>"+XMLTools.encodeXML(getIBAN())+"</ram:IBANID>\n" //$NON-NLS-1$
+ " </ram:PayerPartyDebtorFinancialAccount>\n"; //$NON-NLS-1$
xml = xml + " </ram:SpecifiedTradeSettlementPaymentMeans>\n"; //$NON-NLS-1$
return xml;
}
default String getPaymentXML() {
return "<ram:DirectDebitMandateID>"+XMLTools.encodeXML(getMandate())+"</ram:DirectDebitMandateID>";
}
/***
* @return IBAN of the debtor (optional)
*/
String getIBAN();
/***
* @return sepa direct debit mandate reference
*/
String getMandate();
}

View File

@@ -18,7 +18,11 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
public interface IZUGFeRDTradeSettlementPayment {
import java.text.SimpleDateFormat;
import org.mustangproject.XMLTools;
public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement {
/**
* get payment information text. e.g. Bank transfer
@@ -77,5 +81,31 @@ public interface IZUGFeRDTradeSettlementPayment {
default String getOwnKto() {
return null;
}
default String getSettlementXML() {
String xml = " <ram:SpecifiedTradeSettlementPaymentMeans>\n" //$NON-NLS-1$
+ " <ram:TypeCode>42</ram:TypeCode>\n" //$NON-NLS-1$
+ " <ram:Information>Überweisung</ram:Information>\n" //$NON-NLS-1$
+ " <ram:PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
+ " <ram:IBANID>" + XMLTools.encodeXML(getOwnIBAN()) + "</ram:IBANID>\n"; //$NON-NLS-1$ //$NON-NLS-2$
if (getOwnKto()!=null) {
xml+= " <ram:ProprietaryID>" + XMLTools.encodeXML(getOwnKto()) + "</ram:ProprietaryID>\n"; //$NON-NLS-1$ //$NON-NLS-2$
}
xml+= " </ram:PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
+ " <ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
+ " <ram:BICID>" + XMLTools.encodeXML(getOwnBIC()) + "</ram:BICID>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <ram:Name>"+trans.getOwnBankName()+"</ram:Name>\n" //$NON-NLS-1$
// //$NON-NLS-2$
+ " </ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
+ " </ram:SpecifiedTradeSettlementPaymentMeans>\n"; //$NON-NLS-1$
return xml;
}
/* I'd love to implement getPaymentXML() and put <ram:DueDateDateTime> there because this is where it belongs
* unfortunately, the due date is part of the transaction which is not accessible here :-(
*/
}

View File

@@ -0,0 +1,97 @@
package org.mustangproject.ZUGFeRD;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct;
import java.math.BigDecimal;
public class Item implements IZUGFeRDExportableItem {
protected BigDecimal price, quantity, tax, grossPrice, lineTotalAmount;
protected String id;
protected Product product;
public Item(Product product, BigDecimal price, BigDecimal quantity) {
this.price = price;
this.quantity = quantity;
this.product = product;
}
public BigDecimal getLineTotalAmount() {
return lineTotalAmount;
}
public Item setLineTotalAmount(BigDecimal lineTotalAmount) {
this.lineTotalAmount = lineTotalAmount;
return this;
}
public BigDecimal getGrossPrice() {
return grossPrice;
}
public Item setGrossPrice(BigDecimal grossPrice) {
this.grossPrice = grossPrice;
return this;
}
public BigDecimal getTax() {
return tax;
}
public Item setTax(BigDecimal tax) {
this.tax = tax;
return this;
}
public Item setId(String id) {
this.id = id;
return this;
}
public String getId() {
return id;
}
@Override
public BigDecimal getPrice() {
return price;
}
public Item setPrice(BigDecimal price) {
this.price = price;
return this;
}
@Override
public BigDecimal getQuantity() {
return quantity;
}
public Item setQuantity(BigDecimal quantity) {
this.quantity = quantity;
return this;
}
@Override
public Product getProduct() {
return product;
}
@Override
public IZUGFeRDAllowanceCharge[] getItemAllowances() {
return null;
}
@Override
public IZUGFeRDAllowanceCharge[] getItemCharges() {
return null;
}
public Item setProduct(Product product) {
this.product = product;
return this;
}
}

View File

@@ -0,0 +1,39 @@
package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
public class LineCalc {
private BigDecimal totalGross;
private BigDecimal priceGross;
private BigDecimal itemTotalNetAmount;
private BigDecimal itemTotalVATAmount;
public LineCalc(IZUGFeRDExportableItem currentItem) {
BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100))
.add(new BigDecimal(1));
priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159
totalGross = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity())
.multiply(multiplicator);
itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity())
.setScale(2, BigDecimal.ROUND_HALF_UP);
itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount);
}
public BigDecimal getItemTotalNetAmount() {
return itemTotalNetAmount;
}
public BigDecimal getItemTotalVATAmount() {
return itemTotalVATAmount;
}
public BigDecimal getItemTotalGrossAmount() {
return itemTotalVATAmount;
}
public BigDecimal getPriceGross() {
return priceGross;
}
}

View File

@@ -0,0 +1,75 @@
package org.mustangproject.ZUGFeRD;
public class PostalTradeAddress implements IZUGFeRDExportablePostalTradeAddress {
private String postCodeCode;
private String lineOne;
private String lineTwo;
private String lineThree;
private String cityName;
private String countryID;
private String CountrySubDivisionName;
public void setPostCodeCode(String postCodeCode) {
this.postCodeCode = postCodeCode;
}
public void setLineOne(String lineOne) {
this.lineOne = lineOne;
}
public void setLineTwo(String lineTwo) {
this.lineTwo = lineTwo;
}
public void setLineThree(String lineThree) {
this.lineThree = lineThree;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public void setCountryID(String countryID) {
this.countryID = countryID;
}
public void setCountrySubDivisionName(String countrySubDivisionName) {
CountrySubDivisionName = countrySubDivisionName;
}
@Override
public String getPostcodeCode() {
return this.postCodeCode;
}
@Override
public String getLineOne() {
return this.lineOne;
}
@Override
public String getLineTwo() {
return this.lineTwo;
}
@Override
public String getLineThree() {
return this.lineThree;
}
@Override
public String getCityName() {
return this.cityName;
}
@Override
public String getCountryID() {
return this.countryID;
}
@Override
public String getCountrySubDivisionName() {
return this.CountrySubDivisionName;
}
}

View File

@@ -0,0 +1,76 @@
package org.mustangproject.ZUGFeRD;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct;
import java.math.BigDecimal;
public class Product implements IZUGFeRDExportableProduct {
protected String unit, name, description, sellerAssignedID, buyerAssignedID;
protected BigDecimal VATPercent;
public Product(String name, String description, String unit, BigDecimal VATPercent) {
this.unit = unit;
this.name = name;
this.description = description;
this.VATPercent = VATPercent;
}
public String getSellerAssignedID() {
return sellerAssignedID;
}
public Product setSellerAssignedID(String sellerAssignedID) {
this.sellerAssignedID = sellerAssignedID;
return this;
}
public String getBuyerAssignedID() {
return buyerAssignedID;
}
public Product setBuyerAssignedID(String buyerAssignedID) {
this.buyerAssignedID = buyerAssignedID;
return this;
}
@Override
public String getUnit() {
return unit;
}
public Product setUnit(String unit) {
this.unit = unit;
return this;
}
@Override
public String getName() {
return name;
}
public Product setName(String name) {
this.name = name;
return this;
}
@Override
public String getDescription() {
return description;
}
public Product setDescription(String description) {
this.description = description;
return this;
}
@Override
public BigDecimal getVATPercent() {
return VATPercent;
}
public Product setVATPercent(BigDecimal VATPercent) {
this.VATPercent = VATPercent;
return this;
}
}

View File

@@ -38,10 +38,18 @@ public class VATAmount {
this.categoryCode = categoryCode;
}
BigDecimal basis, calculated;
BigDecimal basis, calculated, applicablePercent;
String categoryCode;
public BigDecimal getApplicablePercent() {
return applicablePercent;
}
public void setApplicablePercent(BigDecimal applicablePercent) {
this.applicablePercent = applicablePercent;
}
public BigDecimal getBasis() {
return basis;
}

View File

@@ -34,12 +34,14 @@ public class XMPSchemaZugferd extends XMPSchema {
/***
* This is what needs to be added to the RDF metadata - basically the name of the embedded Zugferd file
* @param metadata the xmp to be added to
* @param zfVersion which ZF version to use (2 for FX)
* @param isFacturX whether to export as Factur-X
* @param conformanceLevel e.g. conformanceLevel.EN16931
* @param URN the xml URI for the XMP
* @param prefix the xml namespace prefix for the XMP, zf for ZUGFeRD, fx for Factur-X
* @param filename the filename of the invoice
*/
public XMPSchemaZugferd(XMPMetadata metadata, ZUGFeRDConformanceLevel conformanceLevel, String URN, String prefix, String filename) {
public XMPSchemaZugferd(XMPMetadata metadata, int zfVersion, boolean isFacturX, ZUGFeRDConformanceLevel conformanceLevel, String URN, String prefix, String filename) {
super(metadata, URN, prefix, "ZUGFeRD Schema");
setAboutAsSimple("");
@@ -53,6 +55,10 @@ public class XMPSchemaZugferd extends XMPSchema {
setTextPropertyValue("ConformanceLevel", conformanceLevelValue);
setTextPropertyValue("DocumentType", "INVOICE");
setTextPropertyValue("DocumentFileName", filename);
setTextPropertyValue("Version", "1.0");
String version="1.0";
if ((zfVersion==2)&&(!isFacturX)) {
version="2p0";
}
setTextPropertyValue("Version", version);
}
}

View File

@@ -0,0 +1,592 @@
/** **********************************************************************
*
* Copyright 2018 Jochen Staerk
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.mustangproject.XMLTools;
import org.mustangproject.ZUGFeRD.*;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
//// MAIN CLASS
protected byte[] zugferdData;
private IZUGFeRDExportableTransaction trans;
private ZUGFeRDConformanceLevel level;
private String paymentTermsDescription;
@Override
public void setProfile(ZUGFeRDConformanceLevel level) {
this.level = level;
}
/**
* enables the flag to indicate a test invoice in the XML structure
*/
@Override
public void setTest() {
}
private String vatFormat(BigDecimal value) {
return XMLTools.nDigitFormat(value, 2);
}
private String currencyFormat(BigDecimal value) {
return XMLTools.nDigitFormat(value, 2);
}
private String priceFormat(BigDecimal value) {
return XMLTools.nDigitFormat(value, 4);
}
private String quantityFormat(BigDecimal value) {
return XMLTools.nDigitFormat(value, 4);
}
@Override
public byte[] getXML() {
byte[] res = zugferdData;
StringWriter sw = new StringWriter();
Document document = null;
try {
document = DocumentHelper.parseText(new String(zugferdData));
} catch (DocumentException e1) {
Logger.getLogger(ZUGFeRD1PullProvider.class.getName()).log(Level.SEVERE, null, e1);
}
try {
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter(sw, format);
writer.write(document);
res = sw.toString().getBytes("UTF-8");
} catch (IOException e) {
Logger.getLogger(ZUGFeRD1PullProvider.class.getName()).log(Level.SEVERE, null, e);
}
return res;
}
private BigDecimal getTotalPrepaid() {
if (trans.getTotalPrepaidAmount() == null) {
return new BigDecimal(0);
} else {
return trans.getTotalPrepaidAmount();
}
}
private BigDecimal getTotalGross() {
BigDecimal res = getTotal();
HashMap<BigDecimal, VATAmount> VATPercentAmountMap = getVATPercentAmountMap();
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
res = res.add(amount.getCalculated());
}
return res;
}
private BigDecimal getTotal() {
BigDecimal res = new BigDecimal(0);
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
LineCalc lc = new LineCalc(currentItem);
res = res.add(lc.getItemTotalNetAmount());
}
return res;
}
/**
* which taxes have been used with which amounts in this transaction, empty for
* no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable to 19% VAT
* (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT) 190 Eur
*
* @return which taxes have been used with which amounts in this invoice
*/
private HashMap<BigDecimal, VATAmount> getVATPercentAmountMap() {
HashMap<BigDecimal, VATAmount> hm = new HashMap<>();
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
BigDecimal percent = currentItem.getProduct().getVATPercent();
LineCalc lc = new LineCalc(currentItem);
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(),
trans.getDocumentCode());
VATAmount current = hm.get(percent);
if (current == null) {
hm.put(percent, itemVATAmount);
} else {
hm.put(percent, current.add(itemVATAmount));
}
}
return hm;
}
@Override
public String getProfile() {
return "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort";
}
protected String getContactAsXML(IZUGFeRDExportableContact contact) {
String xml = " <ram:Name>" + XMLTools.encodeXML(contact.getName()) + "</ram:Name>\n" //$NON-NLS-2$
// + " <DefinedTradeContact>\n"
// + " <PersonName>xxx</PersonName>\n"
// + " </DefinedTradeContact>\n"
+ " <ram:PostalTradeAddress>\n"
+ " <ram:PostcodeCode>" + XMLTools.encodeXML(contact.getZIP())
+ "</ram:PostcodeCode>\n"
+ " <ram:LineOne>" + XMLTools.encodeXML(contact.getStreet())
+ "</ram:LineOne>\n";
if (trans.getRecipient().getAdditionalAddress() != null) {
xml += " <ram:LineTwo>" + XMLTools.encodeXML(contact.getAdditionalAddress())
+ "</ram:LineTwo>\n";
}
xml += " <ram:CityName>" + XMLTools.encodeXML(contact.getLocation())
+ "</ram:CityName>\n"
+ " <ram:CountryID>" + XMLTools.encodeXML(contact.getCountry())
+ "</ram:CountryID>\n"
+ " </ram:PostalTradeAddress>\n";
if (contact.getVATID() != null) {
xml += " <ram:SpecifiedTaxRegistration>\n"
+ " <ram:ID schemeID=\"VA\">" + XMLTools.encodeXML(contact.getVATID())
+ "</ram:ID>\n"
+ " </ram:SpecifiedTaxRegistration>\n";
}
return xml;
}
@Override
public void generateXML(IZUGFeRDExportableTransaction trans) {
this.trans = trans;
boolean hasDueDate=false;
String taxCategoryCode="";
SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd");
String exemptionReason="";
if (trans.getPaymentTermDescription()!=null) {
paymentTermsDescription=trans.getPaymentTermDescription();
}
if (paymentTermsDescription==null) {
paymentTermsDescription= "Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate());
}
String senderReg = "";
if (trans.getOwnOrganisationFullPlaintextInfo() != null) {
senderReg = "" + "<ram:IncludedNote>\n" + " <ram:Content>\n"
+ XMLTools.encodeXML(trans.getOwnOrganisationFullPlaintextInfo()) + " </ram:Content>\n"
+ "<ram:SubjectCode>REG</ram:SubjectCode>\n" + "</ram:IncludedNote>\n";
}
String rebateAgreement = "";
if (trans.rebateAgreementExists()) {
rebateAgreement = "<ram:IncludedNote>\n" + " <ram:Content>"
+ "Es bestehen Rabatt- und Bonusvereinbarungen.</ram:Content>\n"
+ "<ram:SubjectCode>AAK</ram:SubjectCode>\n" + "</ram:IncludedNote>\n";
}
String subjectNote = "";
if (trans.getSubjectNote()!=null) {
subjectNote = "<ram:IncludedNote>\n" + " <ram:Content>"
+ XMLTools.encodeXML(trans.getSubjectNote())+ "</ram:Content>\n"
+ "</ram:IncludedNote>\n";
}
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<rsm:CrossIndustryDocument xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:rsm=\"urn:ferd:CrossIndustryDocument:invoice:1p0\""
// + "
// xsi:schemaLocation=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100
// ../Schema/ZUGFeRD1p0.xsd\""
+ " xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12\""
+ " xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15\">\n"
+ " <rsm:SpecifiedExchangedDocumentContext>\n"
// + "
// <ram:TestIndicator><udt:Indicator>"+testBooleanStr+"</udt:Indicator></ram:TestIndicator>\n"
//
+ " <ram:GuidelineSpecifiedDocumentContextParameter>\n"
+ " <ram:ID>" + getProfile() + "</ram:ID>\n"
+ " </ram:GuidelineSpecifiedDocumentContextParameter>\n"
+ " </rsm:SpecifiedExchangedDocumentContext>\n"
+ " <rsm:HeaderExchangedDocument>\n"
+ " <ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>\n" //$NON-NLS-2$
+ " <ram:Name>RECHNUNG</ram:Name>\n"
+ " <ram:TypeCode>380</ram:TypeCode>\n"
+ " <ram:IssueDateTime><udt:DateTimeString format=\"102\">"
+ zugferdDateFormat.format(trans.getIssueDate()) + "</udt:DateTimeString></ram:IssueDateTime>\n" // date
// format
// was
// 20130605
+ subjectNote
+ rebateAgreement
+ senderReg
+ " </rsm:HeaderExchangedDocument>\n"
+ " <rsm:SpecifiedSupplyChainTradeTransaction>\n";
xml = xml + " <ram:ApplicableSupplyChainTradeAgreement>\n";
if (trans.getReferenceNumber() != null) {
xml = xml + " <ram:BuyerReference>" + XMLTools.encodeXML(trans.getReferenceNumber()) + "</ram:BuyerReference>\n";
}
xml = xml + " <ram:SellerTradeParty>\n";
if (trans.getOwnForeignOrganisationID()!=null) {
xml = xml + " <ram:ID>" + XMLTools.encodeXML(trans.getOwnForeignOrganisationID()) + "</ram:ID>\n";
}
if ((trans.getOwnContact()!=null)&&(trans.getOwnContact().getGlobalID()!=null)&&(trans.getOwnContact().getGlobalIDScheme()!=null)) {
xml = xml + " <ram:GlobalID schemeID=\"" + XMLTools.encodeXML(trans.getOwnContact().getGlobalIDScheme()) + "\">"
+ XMLTools.encodeXML(trans.getOwnContact().getGlobalID()) + "</ram:GlobalID>\n";
}
xml = xml + " <ram:Name>" + XMLTools.encodeXML(trans.getOwnOrganisationName()) + "</ram:Name>\n"; //$NON-NLS-2$
if (trans.getOwnContact() != null) {
xml = xml + "<ram:DefinedTradeContact>\n" + " <ram:PersonName>" + XMLTools.encodeXML(trans.getOwnContact().getName())
+ "</ram:PersonName>\n";
if (trans.getOwnContact().getPhone() != null) {
xml = xml + " <ram:TelephoneUniversalCommunication>\n" + " <ram:CompleteNumber>"
+ XMLTools.encodeXML(trans.getOwnContact().getPhone()) + "</ram:CompleteNumber>\n"
+ " </ram:TelephoneUniversalCommunication>\n";
}
if (trans.getOwnContact().getEMail() != null) {
xml = xml + " <ram:EmailURIUniversalCommunication>\n" + " <ram:URIID>"
+ XMLTools.encodeXML(trans.getOwnContact().getEMail()) + "</ram:URIID>\n"
+ " </ram:EmailURIUniversalCommunication>\n";
}
xml = xml + " </ram:DefinedTradeContact>";
}
xml = xml + " <ram:PostalTradeAddress>\n" + " <ram:PostcodeCode>"
+ XMLTools.encodeXML(trans.getOwnZIP()) + "</ram:PostcodeCode>\n" + " <ram:LineOne>"
+ XMLTools.encodeXML(trans.getOwnStreet()) + "</ram:LineOne>\n" + " <ram:CityName>" + XMLTools.encodeXML(trans.getOwnLocation())
+ "</ram:CityName>\n" + " <ram:CountryID>" + XMLTools.encodeXML(trans.getOwnCountry())
+ "</ram:CountryID>\n" + " </ram:PostalTradeAddress>\n"
+ " <ram:SpecifiedTaxRegistration>\n"
+ " <ram:ID schemeID=\"FC\">" + XMLTools.encodeXML(trans.getOwnTaxID()) + "</ram:ID>\n" //$NON-NLS-2$
+ " </ram:SpecifiedTaxRegistration>\n"
+ " <ram:SpecifiedTaxRegistration>\n"
+ " <ram:ID schemeID=\"VA\">" + XMLTools.encodeXML(trans.getOwnVATID()) + "</ram:ID>\n" //$NON-NLS-2$
+ " </ram:SpecifiedTaxRegistration>\n"
+ " </ram:SellerTradeParty>\n"
+ " <ram:BuyerTradeParty>\n";
// + " <ID>GE2020211</ID>\n"
// + " <GlobalID schemeID=\"0088\">4000001987658</GlobalID>\n"
xml+=getContactAsXML(trans.getRecipient());
if ((trans.getOwnVATID()!=null)&&(trans.getOwnOrganisationName()!=null)) {
xml = xml + " <ram:SpecifiedTaxRegistration>\n" + " <ram:ID schemeID=\"VA\">"
+ XMLTools.encodeXML(trans.getOwnVATID()) + "</ram:ID>\n"
+ " </ram:SpecifiedTaxRegistration>";
}
xml += " </ram:BuyerTradeParty>\n";
if (trans.getBuyerOrderReferencedDocumentID()!=null) {
xml = xml + " <ram:BuyerOrderReferencedDocument>\n"
+ " <ram:IssuerAssignedID>"
+ XMLTools.encodeXML(trans.getBuyerOrderReferencedDocumentID()) + "</ram:IssuerAssignedID>\n"
+ " </ram:BuyerOrderReferencedDocument>\n";
}
xml = xml + " </ram:ApplicableSupplyChainTradeAgreement>\n"
+ " <ram:ApplicableSupplyChainTradeDelivery>\n" ;
if (this.trans.getDeliveryAddress()!=null) {
xml += "<ram:ShipToTradeParty>"+
getContactAsXML(this.trans.getDeliveryAddress())+
"</ram:ShipToTradeParty>";
}
xml+= " <ram:ActualDeliverySupplyChainEvent>\n"
+ " <ram:OccurrenceDateTime>";
if (trans.getZFDeliveryDate() != null) {
ZUGFeRDDateFormat dateFormat = trans.getZFDeliveryDate().getFormat();
Date date = trans.getZFDeliveryDate().getDate();
xml += "<udt:DateTimeString format=\"" + dateFormat.getDateTimeType() + "\">"
+ dateFormat.getFormatter().format(date) + "</udt:DateTimeString>";
} else if (trans.getDeliveryDate() != null) {
xml += "<udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(trans.getDeliveryDate())
+ "</udt:DateTimeString>";
} else {
throw new IllegalStateException("No delivery date provided");
}
xml += "</ram:OccurrenceDateTime>\n";
xml += " </ram:ActualDeliverySupplyChainEvent>\n"
/*
* + " <DeliveryNoteReferencedDocument>\n" +
* " <IssueDateTime format=\"102\">20130603</IssueDateTime>\n" +
* " <ID>2013-51112</ID>\n" +
* " </DeliveryNoteReferencedDocument>\n"
*/
+ " </ram:ApplicableSupplyChainTradeDelivery>\n" + " <ram:ApplicableSupplyChainTradeSettlement>\n" //$NON-NLS-2$
+ " <ram:PaymentReference>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:PaymentReference>\n" //$NON-NLS-2$
+ " <ram:InvoiceCurrencyCode>" + trans.getCurrency() + "</ram:InvoiceCurrencyCode>\n";
if (trans.getTradeSettlementPayment()!=null) {
for (IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) {
if(payment!=null) {
hasDueDate=true;
xml+=payment.getSettlementXML();
}
}
}
if (trans.getTradeSettlement()!=null) {
for (IZUGFeRDTradeSettlement payment : trans.getTradeSettlement()) {
if(payment!=null) {
if (payment instanceof IZUGFeRDTradeSettlementPayment) {
hasDueDate=true;
}
xml+=payment.getSettlementXML();
}
}
}
HashMap<BigDecimal, VATAmount> VATPercentAmountMap = getVATPercentAmountMap();
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
if (amount != null) {
xml += " <ram:ApplicableTradeTax>\n"
+ " <ram:CalculatedAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(amount.getCalculated())
+ "</ram:CalculatedAmount>\n" //currencyID=\"EUR\"
+ " <ram:TypeCode>VAT</ram:TypeCode>\n"
+ exemptionReason
+ " <ram:BasisAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>\n" // currencyID=\"EUR\"
+ " <ram:CategoryCode>"+taxCategoryCode+"</ram:CategoryCode>\n"
+ " <ram:ApplicablePercent>" + vatFormat(currentTaxPercent)
+ "</ram:ApplicablePercent>\n" + " </ram:ApplicableTradeTax>\n"; //$NON-NLS-2$
}
}
if (trans.getPaymentTerms() == null) {
xml = xml + " <ram:SpecifiedTradePaymentTerms>\n"
+ " <ram:Description>" + paymentTermsDescription + "</ram:Description>\n";
if (trans.getTradeSettlement() != null) {
for (IZUGFeRDTradeSettlement payment : trans.getTradeSettlement()) {
if ((payment != null) && (payment instanceof IZUGFeRDTradeSettlementDebit)) {
xml += payment.getPaymentXML();
}
}
}
if (hasDueDate && (trans.getDueDate()!=null)) {
xml = xml + " <ram:DueDateDateTime><udt:DateTimeString format=\"102\">" // $NON-NLS-2$
+ zugferdDateFormat.format(trans.getDueDate())
+ "</udt:DateTimeString></ram:DueDateDateTime>\n";// 20130704
}
xml = xml + " </ram:SpecifiedTradePaymentTerms>\n";
} else {
xml = xml + buildPaymentTermsXml();
}
xml = xml + " <ram:SpecifiedTradeSettlementMonetarySummation>\n"
+ " <ram:LineTotalAmount currencyID=\""+trans.getCurrency()+"\">" + currencyFormat(getTotal()) + "</ram:LineTotalAmount>\n" //$NON-NLS-2$
// currencyID=\"EUR\"
+ " <ram:ChargeTotalAmount currencyID=\"" + trans.getCurrency() + "\">0.00</ram:ChargeTotalAmount>\n" // currencyID=\"EUR\"
+ " <ram:AllowanceTotalAmount currencyID=\"" + trans.getCurrency() + "\">0.00</ram:AllowanceTotalAmount>\n" //
// currencyID=\"EUR\"
// + " <ChargeTotalAmount currencyID=\"EUR\">5.80</ChargeTotalAmount>\n"
// + " <AllowanceTotalAmount currencyID=\"EUR\">14.73</AllowanceTotalAmount>\n"
+ " <ram:TaxBasisTotalAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(getTotal()) + "</ram:TaxBasisTotalAmount>\n" //$NON-NLS-2$
// //
// currencyID=\"EUR\"
+ " <ram:TaxTotalAmount currencyID=\"" + trans.getCurrency() + "\">"
+ currencyFormat(getTotalGross().subtract(getTotal())) + "</ram:TaxTotalAmount>\n"
+ " <ram:GrandTotalAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(getTotalGross()) + "</ram:GrandTotalAmount>\n" //$NON-NLS-2$
// //
// currencyID=\"EUR\"
+ " <ram:TotalPrepaidAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(getTotalPrepaid()) + "</ram:TotalPrepaidAmount>\n"
+ " <ram:DuePayableAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(getTotalGross().subtract(getTotalPrepaid())) + "</ram:DuePayableAmount>\n" //$NON-NLS-2$
// //
// currencyID=\"EUR\"
+ " </ram:SpecifiedTradeSettlementMonetarySummation>\n"
+ " </ram:ApplicableSupplyChainTradeSettlement>\n";
int lineID = 0;
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
lineID++;
taxCategoryCode=currentItem.getProduct().getTaxCategoryCode();
if (currentItem.getProduct().getTaxExemptionReason() != null) {
exemptionReason="<ram:ExemptionReason>" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + "</ram:ExemptionReason>";
}
LineCalc lc = new LineCalc(currentItem);
xml = xml + " <ram:IncludedSupplyChainTradeLineItem>\n" +
" <ram:AssociatedDocumentLineDocument>\n"
+ " <ram:LineID>" + lineID + "</ram:LineID>\n" //$NON-NLS-2$
+ " </ram:AssociatedDocumentLineDocument>\n"
+ " <ram:SpecifiedSupplyChainTradeAgreement>\n"
+ " <ram:GrossPriceProductTradePrice>\n"
+ " <ram:ChargeAmount currencyID=\""+trans.getCurrency()+"\">" + priceFormat(lc.getPriceGross())
+ "</ram:ChargeAmount>\n"
+ " <ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit())
+ "\">" + quantityFormat(currentItem.getBasisQuantity()) +"</ram:BasisQuantity>\n"
// + " <AppliedTradeAllowanceCharge>\n"
// + " <ChargeIndicator>false</ChargeIndicator>\n"
// + " <ActualAmount currencyID=\"EUR\">0.6667</ActualAmount>\n"
// + " <Reason>Rabatt</Reason>\n"
// + " </AppliedTradeAllowanceCharge>\n"
+ " </ram:GrossPriceProductTradePrice>\n"
+ " <ram:NetPriceProductTradePrice>\n"
+ " <ram:ChargeAmount currencyID=\""+trans.getCurrency()+"\">" + priceFormat(currentItem.getPrice())
+ "</ram:ChargeAmount>\n"
+ " <ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit())
+ "\">" + quantityFormat(currentItem.getBasisQuantity()) +"</ram:BasisQuantity>\n"
+ " </ram:NetPriceProductTradePrice>\n"
+ " </ram:SpecifiedSupplyChainTradeAgreement>\n"
+ " <ram:SpecifiedSupplyChainTradeDelivery>\n"
+ " <ram:BilledQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit()) + "\">" //$NON-NLS-2$
+ quantityFormat(currentItem.getQuantity()) + "</ram:BilledQuantity>\n"
+ " </ram:SpecifiedSupplyChainTradeDelivery>\n"
+ " <ram:SpecifiedSupplyChainTradeSettlement>\n"
+ " <ram:ApplicableTradeTax>\n"
+ " <ram:TypeCode>VAT</ram:TypeCode>\n"
+ exemptionReason
+ " <ram:CategoryCode>"+currentItem.getProduct().getTaxCategoryCode()+"</ram:CategoryCode>\n"
+ " <ram:ApplicablePercent>"
+ vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:ApplicablePercent>\n"
+ " </ram:ApplicableTradeTax>\n"
+ " <ram:SpecifiedTradeSettlementMonetarySummation>\n"
+ " <ram:LineTotalAmount currencyID=\""+trans.getCurrency()+"\">" + currencyFormat(lc.getItemTotalNetAmount())
+ "</ram:LineTotalAmount>\n"
+ " </ram:SpecifiedTradeSettlementMonetarySummation>\n";
if (currentItem.getAdditionalReferencedDocumentID()!=null) {
xml=xml + " <ram:AdditionalReferencedDocument><ram:ID>"+currentItem.getAdditionalReferencedDocumentID()+"</ram:ID><ram:TypeCode>130</ram:TypeCode></ram:AdditionalReferencedDocument>\n";
}
xml=xml + " </ram:SpecifiedSupplyChainTradeSettlement>\n"
+ " <ram:SpecifiedTradeProduct>\n";
// + " <GlobalID schemeID=\"0160\">4012345001235</GlobalID>\n"
if (currentItem.getProduct().getSellerAssignedID() != null) {
xml = xml + " <ram:SellerAssignedID>"
+ XMLTools.encodeXML(currentItem.getProduct().getSellerAssignedID()) + "</ram:SellerAssignedID>\n";
}
if (currentItem.getProduct().getBuyerAssignedID() != null) {
xml = xml + " <ram:BuyerAssignedID>"
+ XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "</ram:BuyerAssignedID>\n";
}
xml = xml + " <ram:Name>" + XMLTools.encodeXML(currentItem.getProduct().getName()) + "</ram:Name>\n" //$NON-NLS-2$
+ " <ram:Description>" + XMLTools.encodeXML(currentItem.getProduct().getDescription())
+ "</ram:Description>\n"
+ " </ram:SpecifiedTradeProduct>\n"
+ " </ram:IncludedSupplyChainTradeLineItem>\n";
}
// + " <IncludedSupplyChainTradeLineItem>\n"
// + " <AssociatedDocumentLineDocument>\n"
// + " <IncludedNote>\n"
// + " <Content>Wir erlauben uns Ihnen folgende Positionen aus der Lieferung Nr.
// 2013-51112 in Rechnung zu stellen:</Content>\n"
// + " </IncludedNote>\n"
// + " </AssociatedDocumentLineDocument>\n"
// + " </IncludedSupplyChainTradeLineItem>\n";
xml = xml + " </rsm:SpecifiedSupplyChainTradeTransaction>\n"
+ "</rsm:CrossIndustryDocument>";
byte[] zugferdRaw;
try {
zugferdRaw = xml.getBytes("UTF-8");
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];
System.arraycopy(zugferdRaw, 3, zugferdData, 0, zugferdRaw.length - 3);
} else {
zugferdData = zugferdRaw;
}
} catch (UnsupportedEncodingException e) {
Logger.getLogger(ZUGFeRD1PullProvider.class.getName()).log(Level.SEVERE, null, e);
} // $NON-NLS-1$
}
private String buildPaymentTermsXml() {
String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>";
IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
IZUGFeRDDate dueDate = paymentTerms.getDueDate();
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) {
throw new IllegalStateException(
"if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
}
paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>";
if (dueDate != null) {
paymentTermsXml += "<ram:DueDateDateTime>";
paymentTermsXml += "<udt:DateTimeString format=\"" + dueDate.getFormat().getDateTimeType() + "\">"
+ dueDate.getFormat().getFormatter().format(dueDate.getDate()) + "</udt:DateTimeString>";
paymentTermsXml += "</ram:DueDateDateTime>";
}
if (discountTerms != null) {
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
String currency = trans.getCurrency();
String basisAmount = currencyFormat(getTotalGross());
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
+ "</ram:CalculationPercent>";
if (discountTerms.getBaseDate() != null) {
Date baseDate = discountTerms.getBaseDate().getDate();
ZUGFeRDDateFormat baseDateFormat = discountTerms.getBaseDate().getFormat();
paymentTermsXml += "<ram:BasisDateTime>";
paymentTermsXml += "<udt:DateTimeString format=\"" + baseDateFormat.getDateTimeType() + "\">" + baseDateFormat.getFormatter().format(baseDate) + "</udt:DateTimeString>";
paymentTermsXml += "</ram:BasisDateTime>";
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
}
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
}
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
return paymentTermsXml;
}
}

View File

@@ -18,17 +18,13 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -38,41 +34,18 @@ import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.mustangproject.toecount.Toecount;
import org.mustangproject.XMLTools;
public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
private class LineCalc {
private BigDecimal totalGross;
private BigDecimal itemTotalNetAmount;
private BigDecimal itemTotalVATAmount;
public LineCalc(IZUGFeRDExportableItem currentItem) {
BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100))
.add(new BigDecimal(1));
// priceGross=currentItem.getPrice().multiply(multiplicator);
totalGross = currentItem.getPrice().multiply(multiplicator).multiply(currentItem.getQuantity());
itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).setScale(2,
BigDecimal.ROUND_HALF_UP);
itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount);
}
public BigDecimal getItemTotalNetAmount() {
return itemTotalNetAmount;
}
public BigDecimal getItemTotalVATAmount() {
return itemTotalVATAmount;
}
}
//// MAIN CLASS
protected byte[] zugferdData;
private IZUGFeRDExportableTransaction trans;
private ZUGFeRDConformanceLevel level;
private String paymentTermsDescription;
@Override
public void setProfile(ZUGFeRDConformanceLevel level) {
this.level = level;
}
@@ -80,52 +53,33 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
/**
* enables the flag to indicate a test invoice in the XML structure
*/
@Override
public void setTest() {
}
public static String nDigitFormat(BigDecimal value, int scale) {
/*
* I needed 123,45, locale independent.I tried
* NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is locale
* specific.I also tried DecimalFormat df = new DecimalFormat( "0,00" );
* df.setDecimalSeparatorAlwaysShown(true); df.setGroupingUsed(false);
* DecimalFormatSymbols symbols = new DecimalFormatSymbols();
* symbols.setDecimalSeparator(','); symbols.setGroupingSeparator(' ');
* df.setDecimalFormatSymbols(symbols);
*
* but that would not switch off grouping. Although I liked very much the
* (incomplete) "BNF diagram" in
* http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html in the
* end I decided to calculate myself and take eur+sparator+cents
*
*/
return value.setScale(scale, RoundingMode.HALF_UP).toPlainString();
}
private String vatFormat(BigDecimal value) {
return ZUGFeRD2PullProvider.nDigitFormat(value, 2);
return XMLTools.nDigitFormat(value, 2);
}
private String currencyFormat(BigDecimal value) {
return ZUGFeRD2PullProvider.nDigitFormat(value, 2);
return XMLTools.nDigitFormat(value, 2);
}
private String priceFormat(BigDecimal value) {
return ZUGFeRD2PullProvider.nDigitFormat(value, 4);
return XMLTools.nDigitFormat(value, 4);
}
private String quantityFormat(BigDecimal value) {
return ZUGFeRD2PullProvider.nDigitFormat(value, 4);
return XMLTools.nDigitFormat(value, 4);
}
@Override
public byte[] getXML() {
byte[] res = zugferdData;
StringWriter sw = new StringWriter();
Document document=null;
Document document = null;
try {
document = DocumentHelper.parseText(new String(zugferdData));
} catch (DocumentException e1) {
@@ -140,13 +94,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
} catch (IOException e) {
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e);
}
return res;
}
private BigDecimal getTotalPrepaid() {
if (trans.getTotalPrepaidAmount()==null) {
if (trans.getTotalPrepaidAmount() == null) {
return new BigDecimal(0);
} else {
return trans.getTotalPrepaidAmount();
@@ -198,63 +152,82 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
return hm;
}
@Override
public String getProfile() {
// return "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_1.2";
return "urn:cen.eu:en16931:2017";
}
public static String encodeXML(CharSequence s) {
StringBuilder sb = new StringBuilder();
int len = s.length();
for (int i=0;i<len;i++) {
int c = s.charAt(i);
if (c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
c = ((c-0xd7c0)<<10) | (s.charAt(++i)&0x3ff); // UTF16 decode
}
if (c < 0x80) { // ASCII range: test most common case first
if (c < 0x20 && (c != '\t' && c != '\r' && c != '\n')) {
// Illegal XML character, even encoded. Skip or substitute
sb.append("&#xfffd;"); // Unicode replacement character
} else {
switch(c) {
case '&': sb.append("&amp;"); break;
case '>': sb.append("&gt;"); break;
case '<': sb.append("&lt;"); break;
// Uncomment next two if encoding for an XML attribute
// case '\'' sb.append("&apos;"); break;
// case '\"' sb.append("&quot;"); break;
// Uncomment next three if you prefer, but not required
// case '\n' sb.append("&#10;"); break;
// case '\r' sb.append("&#13;"); break;
// case '\t' sb.append("&#9;"); break;
default: sb.append((char)c);
}
}
} else if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) {
// Illegal XML character, even encoded. Skip or substitute
sb.append("&#xfffd;"); // Unicode replacement character
} else {
sb.append("&#x");
sb.append(Integer.toHexString(c));
sb.append(';');
}
}
return sb.toString();
protected String getContactAsXML(IZUGFeRDExportableContact contact) {
String xml = " <ram:Name>" + XMLTools.encodeXML(contact.getName()) + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <DefinedTradeContact>\n"
// + " <PersonName>xxx</PersonName>\n"
// + " </DefinedTradeContact>\n"
+ " <ram:PostalTradeAddress>\n" //$NON-NLS-1$
+ " <ram:PostcodeCode>" + XMLTools.encodeXML(contact.getZIP()) //$NON-NLS-1$
+ "</ram:PostcodeCode>\n" //$NON-NLS-1$
+ " <ram:LineOne>" + XMLTools.encodeXML(contact.getStreet()) //$NON-NLS-1$
+ "</ram:LineOne>\n"; //$NON-NLS-1$
if (trans.getRecipient().getAdditionalAddress() != null) {
xml += " <ram:LineTwo>" + XMLTools.encodeXML(contact.getAdditionalAddress()) //$NON-NLS-1$
+ "</ram:LineTwo>\n"; //$NON-NLS-1$
}
xml += " <ram:CityName>" + XMLTools.encodeXML(contact.getLocation()) //$NON-NLS-1$
+ "</ram:CityName>\n" //$NON-NLS-1$
+ " <ram:CountryID>" + XMLTools.encodeXML(contact.getCountry()) //$NON-NLS-1$
+ "</ram:CountryID>\n" //$NON-NLS-1$
+ " </ram:PostalTradeAddress>\n"; //$NON-NLS-1$
if (contact.getVATID() != null) {
xml += " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:ID schemeID=\"VA\">" + XMLTools.encodeXML(contact.getVATID()) //$NON-NLS-1$
+ "</ram:ID>\n" //$NON-NLS-1$
+ " </ram:SpecifiedTaxRegistration>\n"; //$NON-NLS-1$
}
return xml;
}
@Override
public void generateXML(IZUGFeRDExportableTransaction trans) {
this.trans = trans;
boolean hasDueDate=false;
String taxCategoryCode="";
SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); //$NON-NLS-1$
SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); //$NON-NLS-1$
String exemptionReason="";
if (trans.getPaymentTermDescription()!=null) {
paymentTermsDescription=trans.getPaymentTermDescription();
}
if (paymentTermsDescription==null) {
paymentTermsDescription= "Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate());
}
String senderReg = "";
if (trans.getOwnOrganisationFullPlaintextInfo() != null) {
senderReg = "" + "<ram:IncludedNote>\n" + " <ram:Content>\n"
+ encodeXML(trans.getOwnOrganisationFullPlaintextInfo()) + " </ram:Content>\n"
+ XMLTools.encodeXML(trans.getOwnOrganisationFullPlaintextInfo()) + " </ram:Content>\n"
+ "<ram:SubjectCode>REG</ram:SubjectCode>\n" + "</ram:IncludedNote>\n";
}
String rebateAgreement = "";
if (trans.rebateAgreementExists()) {
rebateAgreement = "<ram:IncludedNote>\n" + " <ram:Content>"
+ "Es bestehen Rabatt- und Bonusvereinbarungen.</ram:Content>\n"
+ "<ram:SubjectCode>AAK</ram:SubjectCode>\n" + "</ram:IncludedNote>\n";
}
String subjectNote = "";
if (trans.getSubjectNote()!=null) {
subjectNote = "<ram:IncludedNote>\n" + " <ram:Content>"
+ XMLTools.encodeXML(trans.getSubjectNote())+ "</ram:Content>\n"
+ "</ram:IncludedNote>\n";
}
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" //$NON-NLS-1$
+ "<rsm:CrossIndustryInvoice xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:rsm=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100\""
@@ -272,7 +245,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
+ " </ram:GuidelineSpecifiedDocumentContextParameter>\n" //$NON-NLS-1$
+ " </rsm:ExchangedDocumentContext>\n" //$NON-NLS-1$
+ " <rsm:ExchangedDocument>\n" //$NON-NLS-1$
+ " <ram:ID>" + encodeXML(trans.getNumber()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <ram:Name>RECHNUNG</ram:Name>\n" //$NON-NLS-1$
+ " <ram:TypeCode>380</ram:TypeCode>\n" //$NON-NLS-1$
+ " <ram:IssueDateTime><udt:DateTimeString format=\"102\">" //$NON-NLS-1$
@@ -280,45 +253,46 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
// format
// was
// 20130605
+ subjectNote
+ rebateAgreement
+ senderReg
// + " <IncludedNote>\n"
// + " <Content>\n"
// + "Rechnung gemäß Bestellung Nr. 2013-471331 vom 01.03.2013.\n"
// + "\n"
// + " </Content>\n"
// + " </IncludedNote>\n"
// + " <IncludedNote>\n"
// + " <Content>\n"
// + "Es bestehen Rabatt- und Bonusvereinbarungen.\n"
// + " </Content>\n"
// + " <SubjectCode>AAK</SubjectCode>\n"
// + " </IncludedNote>\n"
+ " </rsm:ExchangedDocument>\n" //$NON-NLS-1$
+ " <rsm:SupplyChainTradeTransaction>\n"; //$NON-NLS-1$
int lineID = 0;
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
lineID++;
taxCategoryCode=currentItem.getProduct().getTaxCategoryCode();
if (currentItem.getProduct().getTaxExemptionReason() != null) {
exemptionReason="<ram:ExemptionReason>" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + "</ram:ExemptionReason>";
}
LineCalc lc = new LineCalc(currentItem);
xml = xml + " <ram:IncludedSupplyChainTradeLineItem>\n" + //$NON-NLS-1$
" <ram:AssociatedDocumentLineDocument>\n" //$NON-NLS-1$
+ " <ram:LineID>" + lineID + "</ram:LineID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:AssociatedDocumentLineDocument>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTradeProduct>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTradeProduct>\n"; //$NON-NLS-1$
// + " <GlobalID schemeID=\"0160\">4012345001235</GlobalID>\n"
// + " <SellerAssignedID>KR3M</SellerAssignedID>\n"
// + " <BuyerAssignedID>55T01</BuyerAssignedID>\n"
+ " <ram:Name>" + encodeXML(currentItem.getProduct().getName()) + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:Description>" + encodeXML(currentItem.getProduct().getDescription()) //$NON-NLS-1$
if (currentItem.getProduct().getSellerAssignedID() != null) {
xml = xml + " <ram:SellerAssignedID>"
+ XMLTools.encodeXML(currentItem.getProduct().getSellerAssignedID()) + "</ram:SellerAssignedID>\n";
}
if (currentItem.getProduct().getBuyerAssignedID() != null) {
xml = xml + " <ram:BuyerAssignedID>"
+ XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "</ram:BuyerAssignedID>\n";
}
xml = xml + " <ram:Name>" + XMLTools.encodeXML(currentItem.getProduct().getName()) + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:Description>" + XMLTools.encodeXML(currentItem.getProduct().getDescription()) //$NON-NLS-1$
+ "</ram:Description>\n" //$NON-NLS-1$
+ " </ram:SpecifiedTradeProduct>\n" //$NON-NLS-1$
+ " <ram:SpecifiedLineTradeAgreement>\n" //$NON-NLS-1$
+ " <ram:GrossPriceProductTradePrice>\n" //$NON-NLS-1$
+ " <ram:ChargeAmount>" + priceFormat(currentItem.getPrice()) //$NON-NLS-1$
+ " <ram:ChargeAmount>" + priceFormat(lc.getPriceGross()) //$NON-NLS-1$
+ "</ram:ChargeAmount>\n" //$NON-NLS-1$ //currencyID=\"EUR\"
+ " <ram:BasisQuantity unitCode=\"" + encodeXML(currentItem.getProduct().getUnit()) //$NON-NLS-1$
+ "\">1.0000</ram:BasisQuantity>\n" //$NON-NLS-1$
+ " <ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit()) //$NON-NLS-1$
+ "\">" + quantityFormat(currentItem.getBasisQuantity()) +"</ram:BasisQuantity>\n" //$NON-NLS-1$
// + " <AppliedTradeAllowanceCharge>\n"
// + " <ChargeIndicator>false</ChargeIndicator>\n"
// + " <ActualAmount currencyID=\"EUR\">0.6667</ActualAmount>\n"
@@ -328,61 +302,74 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
+ " <ram:NetPriceProductTradePrice>\n" //$NON-NLS-1$
+ " <ram:ChargeAmount>" + priceFormat(currentItem.getPrice()) //$NON-NLS-1$
+ "</ram:ChargeAmount>\n" //$NON-NLS-1$ // currencyID=\"EUR\"
+ " <ram:BasisQuantity unitCode=\"" + encodeXML(currentItem.getProduct().getUnit()) //$NON-NLS-1$
+ "\">1.0000</ram:BasisQuantity>\n" //$NON-NLS-1$
+ " <ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit()) //$NON-NLS-1$
+ "\">" + quantityFormat(currentItem.getBasisQuantity()) +"</ram:BasisQuantity>\n" //$NON-NLS-1$
+ " </ram:NetPriceProductTradePrice>\n" //$NON-NLS-1$
+ " </ram:SpecifiedLineTradeAgreement>\n" //$NON-NLS-1$
+ " <ram:SpecifiedLineTradeDelivery>\n" //$NON-NLS-1$
+ " <ram:BilledQuantity unitCode=\"" + encodeXML(currentItem.getProduct().getUnit()) + "\">" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:BilledQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit()) + "\">" //$NON-NLS-1$ //$NON-NLS-2$
+ quantityFormat(currentItem.getQuantity()) + "</ram:BilledQuantity>\n" //$NON-NLS-1$
+ " </ram:SpecifiedLineTradeDelivery>\n" //$NON-NLS-1$
+ " <ram:SpecifiedLineTradeSettlement>\n" //$NON-NLS-1$
+ " <ram:ApplicableTradeTax>\n" //$NON-NLS-1$
+ " <ram:TypeCode>VAT</ram:TypeCode>\n" //$NON-NLS-1$
+ " <ram:CategoryCode>S</ram:CategoryCode>\n" //$NON-NLS-1$
+ exemptionReason
+ " <ram:CategoryCode>"+currentItem.getProduct().getTaxCategoryCode()+"</ram:CategoryCode>\n" //$NON-NLS-1$
+ " <ram:RateApplicablePercent>" //$NON-NLS-1$
+ vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>\n" //$NON-NLS-1$
+ " </ram:ApplicableTradeTax>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTradeSettlementLineMonetarySummation>\n" //$NON-NLS-1$
+ " <ram:LineTotalAmount>" + currencyFormat(lc.getItemTotalNetAmount()) //$NON-NLS-1$
+ "</ram:LineTotalAmount>\n" //$NON-NLS-1$ // currencyID=\"EUR\"
+ " </ram:SpecifiedTradeSettlementLineMonetarySummation>\n" //$NON-NLS-1$
+ " </ram:SpecifiedLineTradeSettlement>\n" //$NON-NLS-1$
+ " </ram:SpecifiedTradeSettlementLineMonetarySummation>\n"; //$NON-NLS-1$
if (currentItem.getAdditionalReferencedDocumentID()!=null) {
xml=xml + " <ram:AdditionalReferencedDocument><ram:IssuerAssignedID>"+currentItem.getAdditionalReferencedDocumentID()+"</ram:IssuerAssignedID><ram:TypeCode>130</ram:TypeCode></ram:AdditionalReferencedDocument>\n"; //$NON-NLS-1$
}
xml=xml + " </ram:SpecifiedLineTradeSettlement>\n" //$NON-NLS-1$
+ " </ram:IncludedSupplyChainTradeLineItem>\n"; //$NON-NLS-1$
}
xml = xml + " <ram:ApplicableHeaderTradeAgreement>\n"; //$NON-NLS-1$
if (trans.getReferenceNumber() != null) {
xml = xml + " <ram:BuyerReference>" + encodeXML(trans.getReferenceNumber()) + "</ram:BuyerReference>\n";
xml = xml + " <ram:BuyerReference>" + XMLTools.encodeXML(trans.getReferenceNumber()) + "</ram:BuyerReference>\n";
}
xml = xml + " <ram:SellerTradeParty>\n" //$NON-NLS-1$
// + " <GlobalID schemeID=\"0088\">4000001123452</GlobalID>\n"
+ " <ram:Name>" + encodeXML(trans.getOwnOrganisationName()) + "</ram:Name>\n"; //$NON-NLS-1$ //$NON-NLS-2$
xml = xml + " <ram:SellerTradeParty>\n"; //$NON-NLS-1$
if (trans.getOwnForeignOrganisationID()!=null) {
xml = xml + " <ram:ID>" + XMLTools.encodeXML(trans.getOwnForeignOrganisationID()) + "</ram:ID>\n";
}
if ((trans.getOwnContact()!=null)&&(trans.getOwnContact().getGlobalID()!=null)&&(trans.getOwnContact().getGlobalIDScheme()!=null)) {
xml = xml + " <ram:GlobalID schemeID=\"" + XMLTools.encodeXML(trans.getOwnContact().getGlobalIDScheme()) + "\">"
+ XMLTools.encodeXML(trans.getOwnContact().getGlobalID()) + "</ram:GlobalID>\n";
}
xml = xml + " <ram:Name>" + XMLTools.encodeXML(trans.getOwnOrganisationName()) + "</ram:Name>\n"; //$NON-NLS-1$ //$NON-NLS-2$
if ((trans.getOwnVATID()!=null)&&(trans.getOwnOrganisationName()!=null)) {
xml = xml + " <ram:SpecifiedLegalOrganization>\n" + " <ram:ID schemeID='9930'>"
+ encodeXML(trans.getOwnVATID()) + "</ram:ID>\n" + " <ram:TradingBusinessName>"
+ encodeXML(trans.getOwnOrganisationName()) + "</ram:TradingBusinessName>\n"
xml = xml + " <ram:SpecifiedLegalOrganization>\n" + " <ram:ID>"
+ XMLTools.encodeXML(trans.getOwnVATID()) + "</ram:ID>\n" + " <ram:TradingBusinessName>"
+ XMLTools.encodeXML(trans.getOwnOrganisationName()) + "</ram:TradingBusinessName>\n"
+ " </ram:SpecifiedLegalOrganization>";
}
if (trans.getOwnContact() != null) {
xml = xml + "<ram:DefinedTradeContact>\n" + " <ram:PersonName>" + encodeXML(trans.getOwnContact().getName())
xml = xml + "<ram:DefinedTradeContact>\n" + " <ram:PersonName>" + XMLTools.encodeXML(trans.getOwnContact().getName())
+ "</ram:PersonName>\n";
if (trans.getOwnContact().getPhone() != null) {
xml = xml + " <ram:TelephoneUniversalCommunication>\n" + " <ram:CompleteNumber>"
+ encodeXML(trans.getOwnContact().getPhone()) + "</ram:CompleteNumber>\n"
+ XMLTools.encodeXML(trans.getOwnContact().getPhone()) + "</ram:CompleteNumber>\n"
+ " </ram:TelephoneUniversalCommunication>\n";
}
if (trans.getOwnContact().getEMail() != null) {
xml = xml + " <ram:EmailURIUniversalCommunication>\n" + " <ram:URIID>"
+ encodeXML(trans.getOwnContact().getEMail()) + "</ram:URIID>\n"
+ XMLTools.encodeXML(trans.getOwnContact().getEMail()) + "</ram:URIID>\n"
+ " </ram:EmailURIUniversalCommunication>\n";
}
xml = xml + " </ram:DefinedTradeContact>";
@@ -390,45 +377,54 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
}
xml = xml + " <ram:PostalTradeAddress>\n" + " <ram:PostcodeCode>"
+ encodeXML(trans.getOwnZIP()) + "</ram:PostcodeCode>\n" + " <ram:LineOne>"
+ encodeXML(trans.getOwnStreet()) + "</ram:LineOne>\n" + " <ram:CityName>" + encodeXML(trans.getOwnLocation())
+ "</ram:CityName>\n" + " <ram:CountryID>" + encodeXML(trans.getOwnCountry())
+ XMLTools.encodeXML(trans.getOwnZIP()) + "</ram:PostcodeCode>\n" + " <ram:LineOne>"
+ XMLTools.encodeXML(trans.getOwnStreet()) + "</ram:LineOne>\n" + " <ram:CityName>" + XMLTools.encodeXML(trans.getOwnLocation())
+ "</ram:CityName>\n" + " <ram:CountryID>" + XMLTools.encodeXML(trans.getOwnCountry())
+ "</ram:CountryID>\n" + " </ram:PostalTradeAddress>\n"
+ " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:ID schemeID=\"FC\">" + encodeXML(trans.getOwnTaxID()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:ID schemeID=\"FC\">" + XMLTools.encodeXML(trans.getOwnTaxID()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:ID schemeID=\"VA\">" + encodeXML(trans.getOwnVATID()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:ID schemeID=\"VA\">" + XMLTools.encodeXML(trans.getOwnVATID()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " </ram:SellerTradeParty>\n" //$NON-NLS-1$
+ " <ram:BuyerTradeParty>\n" //$NON-NLS-1$
+ " <ram:BuyerTradeParty>\n"; //$NON-NLS-1$
// + " <ID>GE2020211</ID>\n"
// + " <GlobalID schemeID=\"0088\">4000001987658</GlobalID>\n"
+ " <ram:Name>" + encodeXML(trans.getRecipient().getName()) + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <DefinedTradeContact>\n"
// + " <PersonName>xxx</PersonName>\n"
// + " </DefinedTradeContact>\n"
+ " <ram:PostalTradeAddress>\n" //$NON-NLS-1$
+ " <ram:PostcodeCode>" + encodeXML(trans.getRecipient().getZIP()) + "</ram:PostcodeCode>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:LineOne>" + encodeXML(trans.getRecipient().getStreet()) + "</ram:LineOne>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:CityName>" + encodeXML(trans.getRecipient().getLocation()) + "</ram:CityName>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:CountryID>" + encodeXML(trans.getRecipient().getCountry()) + "</ram:CountryID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:PostalTradeAddress>\n"; //$NON-NLS-1$
if (trans.getRecipient().getVATID() != null) {
xml += " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:ID schemeID=\"VA\">" + encodeXML(trans.getRecipient().getVATID()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:SpecifiedTaxRegistration>\n"; //$NON-NLS-1$
xml+=getContactAsXML(trans.getRecipient());
xml += " </ram:BuyerTradeParty>\n"; //$NON-NLS-1$
if (trans.getBuyerOrderReferencedDocumentID()!=null) {
xml = xml + " <ram:BuyerOrderReferencedDocument>\n" //$NON-NLS-1$
+ " <ram:IssuerAssignedID>" //$NON-NLS-1$
+ XMLTools.encodeXML(trans.getBuyerOrderReferencedDocumentID()) + "</ram:IssuerAssignedID>\n" //$NON-NLS-1$
+ " </ram:BuyerOrderReferencedDocument>\n";
}
xml += " </ram:BuyerTradeParty>\n" //$NON-NLS-1$
// + " <BuyerOrderReferencedDocument>\n"
// + " <IssueDateTime format=\"102\">20130301</IssueDateTime>\n"
// + " <ID>2013-471331</ID>\n"
// + " </BuyerOrderReferencedDocument>\n"
+ " </ram:ApplicableHeaderTradeAgreement>\n" //$NON-NLS-1$
+ " <ram:ApplicableHeaderTradeDelivery>\n" + " <ram:ActualDeliverySupplyChainEvent>\n"
+ " <ram:OccurrenceDateTime><udt:DateTimeString format=\"102\">"
+ zugferdDateFormat.format(trans.getDeliveryDate()) + "</udt:DateTimeString></ram:OccurrenceDateTime>\n"
+ " </ram:ActualDeliverySupplyChainEvent>\n"
xml = xml + " </ram:ApplicableHeaderTradeAgreement>\n" //$NON-NLS-1$
+ " <ram:ApplicableHeaderTradeDelivery>\n" ;
if (this.trans.getDeliveryAddress()!=null) {
xml += "<ram:ShipToTradeParty>"+
getContactAsXML(this.trans.getDeliveryAddress())+
"</ram:ShipToTradeParty>";
}
xml+= " <ram:ActualDeliverySupplyChainEvent>\n"
+ " <ram:OccurrenceDateTime>";
if (trans.getZFDeliveryDate() != null) {
ZUGFeRDDateFormat dateFormat = trans.getZFDeliveryDate().getFormat();
Date date = trans.getZFDeliveryDate().getDate();
xml += "<udt:DateTimeString format=\"" + dateFormat.getDateTimeType() + "\">"
+ dateFormat.getFormatter().format(date) + "</udt:DateTimeString>";
} else if (trans.getDeliveryDate() != null) {
xml += "<udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(trans.getDeliveryDate())
+ "</udt:DateTimeString>";
} else {
throw new IllegalStateException("No delivery date provided");
}
xml += "</ram:OccurrenceDateTime>\n";
xml += " </ram:ActualDeliverySupplyChainEvent>\n"
/*
* + " <DeliveryNoteReferencedDocument>\n" +
* " <IssueDateTime format=\"102\">20130603</IssueDateTime>\n" +
@@ -436,26 +432,26 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
* " </DeliveryNoteReferencedDocument>\n"
*/
+ " </ram:ApplicableHeaderTradeDelivery>\n" + " <ram:ApplicableHeaderTradeSettlement>\n" //$NON-NLS-2$
+ " <ram:PaymentReference>" + encodeXML(trans.getNumber()) + "</ram:PaymentReference>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>\n"; //$NON-NLS-1$
+ " <ram:PaymentReference>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:PaymentReference>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:InvoiceCurrencyCode>" + trans.getCurrency() + "</ram:InvoiceCurrencyCode>\n"; //$NON-NLS-1$
for (IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) {
xml += " <ram:SpecifiedTradeSettlementPaymentMeans>\n" //$NON-NLS-1$
+ " <ram:TypeCode>42</ram:TypeCode>\n" //$NON-NLS-1$
+ " <ram:Information>Überweisung</ram:Information>\n" //$NON-NLS-1$
+ " <ram:PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
+ " <ram:IBANID>" + encodeXML(payment.getOwnIBAN()) + "</ram:IBANID>\n"; //$NON-NLS-1$ //$NON-NLS-2$
if (payment.getOwnKto()!=null) {
xml+= " <ram:ProprietaryID>" + encodeXML(payment.getOwnKto()) + "</ram:ProprietaryID>\n"; //$NON-NLS-1$ //$NON-NLS-2$
if (trans.getTradeSettlementPayment()!=null) {
for (IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) {
if(payment!=null) {
hasDueDate=true;
xml+=payment.getSettlementXML();
}
xml+= " </ram:PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
+ " <ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
+ " <ram:BICID>" + encodeXML(payment.getOwnBIC()) + "</ram:BICID>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <ram:Name>"+trans.getOwnBankName()+"</ram:Name>\n" //$NON-NLS-1$
// //$NON-NLS-2$
+ " </ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
+ " </ram:SpecifiedTradeSettlementPaymentMeans>\n"; //$NON-NLS-1$
}
}
if (trans.getTradeSettlement()!=null) {
for (IZUGFeRDTradeSettlement payment : trans.getTradeSettlement()) {
if(payment!=null) {
if (payment instanceof IZUGFeRDTradeSettlementPayment) {
hasDueDate=true;
}
xml+=payment.getSettlementXML();
}
}
}
HashMap<BigDecimal, VATAmount> VATPercentAmountMap = getVATPercentAmountMap();
@@ -466,53 +462,39 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
+ " <ram:CalculatedAmount>" + currencyFormat(amount.getCalculated()) //$NON-NLS-1$
+ "</ram:CalculatedAmount>\n" //$NON-NLS-1$ //currencyID=\"EUR\"
+ " <ram:TypeCode>VAT</ram:TypeCode>\n" //$NON-NLS-1$
+ exemptionReason
+ " <ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>\n" // currencyID=\"EUR\"
+ " <ram:CategoryCode>S</ram:CategoryCode>\n" //$NON-NLS-1$
+ " <ram:CategoryCode>"+taxCategoryCode+"</ram:CategoryCode>\n" //$NON-NLS-1$
+ " <ram:RateApplicablePercent>" + vatFormat(currentTaxPercent) //$NON-NLS-1$
+ "</ram:RateApplicablePercent>\n" + " </ram:ApplicableTradeTax>\n"; //$NON-NLS-2$
}
}
/*
* xml+= " + " <SpecifiedTradeAllowanceCharge>\n" +
* " <ChargeIndicator>false</ChargeIndicator>\n" +
* " <BasisAmount currencyID=\"EUR\">10</BasisAmount>\n" +
* " <ActualAmount>1.00</ActualAmount>\n" +
* " <Reason>Sondernachlass</Reason>\n" +
* " <CategoryTradeTax>\n" +
* " <TypeCode>VAT</TypeCode>\n" +
* " <CategoryCode>S</CategoryCode>\n" +
* " <ApplicablePercent>19</ApplicablePercent>\n" +
* " </CategoryTradeTax>\n" +
* " </SpecifiedTradeAllowanceCharge>\n" +
* " <SpecifiedTradeAllowanceCharge>\n" +
* " <ChargeIndicator>false</ChargeIndicator>\n" +
* " <BasisAmount currencyID=\"EUR\">137.30</BasisAmount>\n" +
* " <ActualAmount>13.73</ActualAmount>\n" +
* " <Reason>Sondernachlass</Reason>\n" +
* " <CategoryTradeTax>\n" +
* " <TypeCode>VAT</TypeCode>\n" +
* " <CategoryCode>S</CategoryCode>\n" +
* " <ApplicablePercent>7</ApplicablePercent>\n" +
* " </CategoryTradeTax>\n" +
* " </SpecifiedTradeAllowanceCharge>\n" +
* " <SpecifiedLogisticsServiceCharge>\n" +
* " <Description>Versandkosten</Description>\n" +
* " <AppliedAmount>5.80</AppliedAmount>\n" +
* " <AppliedTradeTax>\n" +
* " <TypeCode>VAT</TypeCode>\n" +
* " <CategoryCode>S</CategoryCode>\n" +
* " <ApplicablePercent>7</ApplicablePercent>\n" +
* " </AppliedTradeTax>\n" +
* " </SpecifiedLogisticsServiceCharge>\n"
*/
xml = xml + " <ram:SpecifiedTradePaymentTerms>\n" //$NON-NLS-1$
+ " <ram:Description>Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate())
+ "</ram:Description>\n" + " <ram:DueDateDateTime><udt:DateTimeString format=\"102\">" //$NON-NLS-2$
+ zugferdDateFormat.format(trans.getDueDate()) + "</udt:DateTimeString></ram:DueDateDateTime>\n"// 20130704 //$NON-NLS-1$
+ " </ram:SpecifiedTradePaymentTerms>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n" //$NON-NLS-1$
if (trans.getPaymentTerms() == null) {
xml = xml + " <ram:SpecifiedTradePaymentTerms>\n" //$NON-NLS-1$
+ " <ram:Description>" + paymentTermsDescription + "</ram:Description>\n";
if (trans.getTradeSettlement() != null) {
for (IZUGFeRDTradeSettlement payment : trans.getTradeSettlement()) {
if ((payment != null) && (payment instanceof IZUGFeRDTradeSettlementDebit)) {
xml += payment.getPaymentXML();
}
}
}
if (hasDueDate && (trans.getDueDate()!=null)) {
xml = xml + " <ram:DueDateDateTime><udt:DateTimeString format=\"102\">" // $NON-NLS-2$
+ zugferdDateFormat.format(trans.getDueDate())
+ "</udt:DateTimeString></ram:DueDateDateTime>\n";// 20130704 //$NON-NLS-1$
}
xml = xml + " </ram:SpecifiedTradePaymentTerms>\n"; //$NON-NLS-1$
} else {
xml = xml + buildPaymentTermsXml();
}
xml = xml + " <ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n" //$NON-NLS-1$
+ " <ram:LineTotalAmount>" + currencyFormat(getTotal()) + "</ram:LineTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
// currencyID=\"EUR\"
+ " <ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>\n" //$NON-NLS-1$ currencyID=\"EUR\"
@@ -523,12 +505,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
+ " <ram:TaxBasisTotalAmount>" + currencyFormat(getTotal()) + "</ram:TaxBasisTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
// //
// currencyID=\"EUR\"
+ " <ram:TaxTotalAmount currencyID=\"EUR\">" //$NON-NLS-1$
+ " <ram:TaxTotalAmount currencyID=\"" + trans.getCurrency() + "\">" //$NON-NLS-1$
+ currencyFormat(getTotalGross().subtract(getTotal())) + "</ram:TaxTotalAmount>\n" //$NON-NLS-1$
+ " <ram:GrandTotalAmount>" + currencyFormat(getTotalGross()) + "</ram:GrandTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
// //
// currencyID=\"EUR\"
+ " <ram:TotalPrepaidAmount currencyID=\"EUR\">" + currencyFormat(getTotalPrepaid()) + "</ram:TotalPrepaidAmount>\n"
+ " <ram:TotalPrepaidAmount>" + currencyFormat(getTotalPrepaid()) + "</ram:TotalPrepaidAmount>\n"
+ " <ram:DuePayableAmount>" + currencyFormat(getTotalGross().subtract(getTotalPrepaid())) + "</ram:DuePayableAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
// //
// currencyID=\"EUR\"
@@ -558,8 +540,52 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
zugferdData = zugferdRaw;
}
} catch (UnsupportedEncodingException e) {
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e);
} // $NON-NLS-1$
}
private String buildPaymentTermsXml() {
String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>";
IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
IZUGFeRDDate dueDate = paymentTerms.getDueDate();
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) {
throw new IllegalStateException(
"if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
}
paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>";
if (dueDate != null) {
paymentTermsXml += "<ram:DueDateDateTime>";
paymentTermsXml += "<udt:DateTimeString format=\"" + dueDate.getFormat().getDateTimeType() + "\">"
+ dueDate.getFormat().getFormatter().format(dueDate.getDate()) + "</udt:DateTimeString>";
paymentTermsXml += "</ram:DueDateDateTime>";
}
if (discountTerms != null) {
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
String currency = trans.getCurrency();
String basisAmount = currencyFormat(getTotalGross());
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
+ "</ram:CalculationPercent>";
if (discountTerms.getBaseDate() != null) {
Date baseDate = discountTerms.getBaseDate().getDate();
ZUGFeRDDateFormat baseDateFormat = discountTerms.getBaseDate().getFormat();
paymentTermsXml += "<ram:BasisDateTime>";
paymentTermsXml += "<udt:DateTimeString format=\"" + baseDateFormat.getDateTimeType() + "\">" + baseDateFormat.getFormatter().format(baseDate) + "</udt:DateTimeString>";
paymentTermsXml += "</ram:BasisDateTime>";
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
}
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
}
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
return paymentTermsXml;
}
}

View File

@@ -0,0 +1,413 @@
/**
* *********************************************************************
* <p>
* Copyright 2018 Jochen Staerk
* <p>
* Use is subject to license terms.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* <p>
* See the License for the specific language governing permissions and
* limitations under the License.
* <p>
* **********************************************************************
*/
package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
public class ZUGFeRD2PushProvider implements IZUGFeRDExportableTransaction {
protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownTaxID = null, ownVATID = null, ownForeignOrganisationID = null, ownOrganisationName = null, ownStreet = null, ownZIP = null, ownLocation = null, ownCountry = null, currency = null, paymentTermDescription = null;
protected Date issueDate = null, dueDate = null, deliveryDate = null;
protected BigDecimal totalPrepaidAmount = null;
protected IZUGFeRDExportableContact ownContact = null, recipient = null, deliveryAddress = null;
protected ArrayList<IZUGFeRDExportableItem> ZFItems = null;
protected IZUGFeRDAllowanceCharge[] ZFAllowances = null, ZFCharges = null, ZFLogisticsServiceCharges = null;
protected IZUGFeRDTradeSettlement[] getTradeSettlement = null;
protected IZUGFeRDPaymentTerms paymentTerms = null;
public ZUGFeRD2PushProvider() {
ZFItems = new ArrayList<IZUGFeRDExportableItem>();
}
@Override
public String getDocumentName() {
return documentName;
}
public ZUGFeRD2PushProvider setDocumentName(String documentName) {
this.documentName = documentName;
return this;
}
@Override
public String getDocumentCode() {
return documentCode;
}
public ZUGFeRD2PushProvider setDocumentCode(String documentCode) {
this.documentCode = documentCode;
return this;
}
@Override
public String getNumber() {
return number;
}
public ZUGFeRD2PushProvider setNumber(String number) {
this.number = number;
return this;
}
@Override
public String getOwnOrganisationFullPlaintextInfo() {
return ownOrganisationFullPlaintextInfo;
}
public ZUGFeRD2PushProvider setOwnOrganisationFullPlaintextInfo(String ownOrganisationFullPlaintextInfo) {
this.ownOrganisationFullPlaintextInfo = ownOrganisationFullPlaintextInfo;
return this;
}
@Override
public String getReferenceNumber() {
return referenceNumber;
}
public ZUGFeRD2PushProvider setReferenceNumber(String referenceNumber) {
this.referenceNumber = referenceNumber;
return this;
}
@Override
public String getShipToOrganisationID() {
return shipToOrganisationID;
}
public ZUGFeRD2PushProvider setShipToOrganisationID(String shipToOrganisationID) {
this.shipToOrganisationID = shipToOrganisationID;
return this;
}
@Override
public String getShipToOrganisationName() {
return shipToOrganisationName;
}
public ZUGFeRD2PushProvider setShipToOrganisationName(String shipToOrganisationName) {
this.shipToOrganisationName = shipToOrganisationName;
return this;
}
@Override
public String getShipToStreet() {
return shipToStreet;
}
public ZUGFeRD2PushProvider setShipToStreet(String shipToStreet) {
this.shipToStreet = shipToStreet;
return this;
}
@Override
public String getShipToZIP() {
return shipToZIP;
}
public ZUGFeRD2PushProvider setShipToZIP(String shipToZIP) {
this.shipToZIP = shipToZIP;
return this;
}
@Override
public String getShipToLocation() {
return shipToLocation;
}
public ZUGFeRD2PushProvider setShipToLocation(String shipToLocation) {
this.shipToLocation = shipToLocation;
return this;
}
@Override
public String getShipToCountry() {
return shipToCountry;
}
public ZUGFeRD2PushProvider setShipToCountry(String shipToCountry) {
this.shipToCountry = shipToCountry;
return this;
}
@Override
public String getBuyerOrderReferencedDocumentID() {
return buyerOrderReferencedDocumentID;
}
public ZUGFeRD2PushProvider setBuyerOrderReferencedDocumentID(String buyerOrderReferencedDocumentID) {
this.buyerOrderReferencedDocumentID = buyerOrderReferencedDocumentID;
return this;
}
@Override
public String getBuyerOrderReferencedDocumentIssueDateTime() {
return buyerOrderReferencedDocumentIssueDateTime;
}
public ZUGFeRD2PushProvider setBuyerOrderReferencedDocumentIssueDateTime(String buyerOrderReferencedDocumentIssueDateTime) {
this.buyerOrderReferencedDocumentIssueDateTime = buyerOrderReferencedDocumentIssueDateTime;
return this;
}
@Override
public String getOwnTaxID() {
return ownTaxID;
}
public ZUGFeRD2PushProvider setOwnTaxID(String ownTaxID) {
this.ownTaxID = ownTaxID;
return this;
}
@Override
public String getOwnVATID() {
return ownVATID;
}
public ZUGFeRD2PushProvider setOwnVATID(String ownVATID) {
this.ownVATID = ownVATID;
return this;
}
@Override
public String getOwnForeignOrganisationID() {
return ownForeignOrganisationID;
}
public ZUGFeRD2PushProvider setOwnForeignOrganisationID(String ownForeignOrganisationID) {
this.ownForeignOrganisationID = ownForeignOrganisationID;
return this;
}
@Override
public String getOwnOrganisationName() {
return ownOrganisationName;
}
public ZUGFeRD2PushProvider setOwnOrganisationName(String ownOrganisationName) {
this.ownOrganisationName = ownOrganisationName;
return this;
}
@Override
public String getOwnStreet() {
return ownStreet;
}
public ZUGFeRD2PushProvider setOwnStreet(String ownStreet) {
this.ownStreet = ownStreet;
return this;
}
@Override
public String getOwnZIP() {
return ownZIP;
}
public ZUGFeRD2PushProvider setOwnZIP(String ownZIP) {
this.ownZIP = ownZIP;
return this;
}
public String getOwnLocation() {
return ownLocation;
}
public ZUGFeRD2PushProvider setOwnLocation(String getOwnLocation) {
this.ownLocation = getOwnLocation;
return this;
}
public String getOwnCountry() {
return ownCountry;
}
public ZUGFeRD2PushProvider setOwnCountry(String getOwnCountry) {
this.ownCountry = getOwnCountry;
return this;
}
@Override
public String getCurrency() {
return currency;
}
public ZUGFeRD2PushProvider setCurrency(String currency) {
this.currency = currency;
return this;
}
@Override
public String getPaymentTermDescription() {
return paymentTermDescription;
}
public ZUGFeRD2PushProvider setPaymentTermDescription(String paymentTermDescription) {
this.paymentTermDescription = paymentTermDescription;
return this;
}
@Override
public Date getIssueDate() {
return issueDate;
}
public ZUGFeRD2PushProvider setIssueDate(Date issueDate) {
this.issueDate = issueDate;
return this;
}
@Override
public Date getDueDate() {
return dueDate;
}
public ZUGFeRD2PushProvider setDueDate(Date dueDate) {
this.dueDate = dueDate;
return this;
}
@Override
public Date getDeliveryDate() {
return deliveryDate;
}
public ZUGFeRD2PushProvider setDeliveryDate(Date deliveryDate) {
this.deliveryDate = deliveryDate;
return this;
}
@Override
public BigDecimal getTotalPrepaidAmount() {
return totalPrepaidAmount;
}
public ZUGFeRD2PushProvider setTotalPrepaidAmount(BigDecimal totalPrepaidAmount) {
this.totalPrepaidAmount = totalPrepaidAmount;
return this;
}
@Override
public IZUGFeRDExportableContact getOwnContact() {
return ownContact;
}
public ZUGFeRD2PushProvider setOwnContact(IZUGFeRDExportableContact ownContact) {
this.ownContact = ownContact;
return this;
}
@Override
public IZUGFeRDExportableContact getRecipient() {
return recipient;
}
public ZUGFeRD2PushProvider setRecipient(IZUGFeRDExportableContact recipient) {
this.recipient = recipient;
return this;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFAllowances() {
return ZFAllowances;
}
public ZUGFeRD2PushProvider setZFAllowances(IZUGFeRDAllowanceCharge[] ZFAllowances) {
this.ZFAllowances = ZFAllowances;
return this;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFCharges() {
return ZFCharges;
}
public ZUGFeRD2PushProvider setZFCharges(IZUGFeRDAllowanceCharge[] ZFCharges) {
this.ZFCharges = ZFCharges;
return this;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
return ZFLogisticsServiceCharges;
}
public ZUGFeRD2PushProvider setZFLogisticsServiceCharges(IZUGFeRDAllowanceCharge[] ZFLogisticsServiceCharges) {
this.ZFLogisticsServiceCharges = ZFLogisticsServiceCharges;
return this;
}
public IZUGFeRDTradeSettlement[] getGetTradeSettlement() {
return getTradeSettlement;
}
public ZUGFeRD2PushProvider setGetTradeSettlement(IZUGFeRDTradeSettlement[] getTradeSettlement) {
this.getTradeSettlement = getTradeSettlement;
return this;
}
@Override
public IZUGFeRDPaymentTerms getPaymentTerms() {
return paymentTerms;
}
public ZUGFeRD2PushProvider setPaymentTerms(IZUGFeRDPaymentTerms paymentTerms) {
this.paymentTerms = paymentTerms;
return this;
}
@Override
public IZUGFeRDExportableContact getDeliveryAddress() {
return deliveryAddress;
}
public ZUGFeRD2PushProvider setDeliveryAddress(IZUGFeRDExportableContact deliveryAddress) {
this.deliveryAddress = deliveryAddress;
return this;
}
@Override
public IZUGFeRDExportableItem[] getZFItems() {
return ZFItems.toArray(new IZUGFeRDExportableItem[0]);
}
public ZUGFeRD2PushProvider addItem(IZUGFeRDExportableItem item) {
ZFItems.add(item);
return this;
}
public boolean isValid() {
return (dueDate != null) && (ownZIP != null) && (ownStreet != null) && (ownLocation != null) && (ownCountry != null) && (ownTaxID != null) && (ownVATID != null) && (recipient != null);
//contact
// this.phone = phone;
// this.email = email;
// this.street = street;
// this.zip = zip;
// this.location = location;
// this.country = country;
}
}

View File

@@ -19,5 +19,5 @@
package org.mustangproject.ZUGFeRD;
public enum ZUGFeRDConformanceLevel {
BASIC, COMFORT, EXTENDED, EN16931/*=Comfort*/, MINIMUM, BASICWL /*basic without lines, less than basic*/, CIUS
BASIC, COMFORT, EXTENDED, EN16931/*=Comfort*/, MINIMUM, BASICWL /*basic without lines, less than basic*/, CIUS, XRECHNUNG
}

View File

@@ -0,0 +1,28 @@
package org.mustangproject.ZUGFeRD;
import java.text.SimpleDateFormat;
import org.mustangproject.ZUGFeRD.model.DateTimeTypeConstants;
public enum ZUGFeRDDateFormat {
MONTH_OF_YEAR(DateTimeTypeConstants.MONTH, new SimpleDateFormat("yyyyMM")),
WEEK_OF_YEAR(DateTimeTypeConstants.WEEK, new SimpleDateFormat("yyyyww")),
DATE(DateTimeTypeConstants.DATE, new SimpleDateFormat("yyyyMMdd"));
private String dateTimeType;
private SimpleDateFormat formatter;
private ZUGFeRDDateFormat(String dateTimeType, SimpleDateFormat formatter) {
this.dateTimeType = dateTimeType;
this.formatter = formatter;
}
public String getDateTimeType() {
return dateTimeType;
}
public SimpleDateFormat getFormatter() {
return formatter;
}
}

View File

@@ -54,9 +54,9 @@ import java.util.Map;
public class ZUGFeRDExporter implements Closeable {
public static final int DefaultZUGFeRDVersion = 1;
public static final int DefaultZUGFeRDVersion = 2;
private boolean isFacturX = false;
private boolean isFacturX = true;
/**
* To use the ZUGFeRD exporter, implement IZUGFeRDExportableTransaction in
@@ -80,7 +80,7 @@ public class ZUGFeRDExporter implements Closeable {
// BASIC, COMFORT etc - may be set from outside.
@Deprecated
private ZUGFeRDConformanceLevel profile = ZUGFeRDConformanceLevel.EXTENDED;
private ZUGFeRDConformanceLevel profile = ZUGFeRDConformanceLevel.EN16931;
/**
* Data (XML invoice) to be added to the ZUGFeRD PDF. It may be externally set,
@@ -132,8 +132,8 @@ public class ZUGFeRDExporter implements Closeable {
/**
* Adds additional file attachments into the ZF
* @param filename
* @param filecontent
* @param filename the name of the attachment
* @param filecontent the bytearray with the file contents
*/
public void addAdditionalFile(String filename, byte[] filecontent) {
additionalFiles.put(filename, filecontent);
@@ -192,6 +192,7 @@ public class ZUGFeRDExporter implements Closeable {
public void setZUGFeRDVersion(int ver) {
if (ver == 1) {
ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider();
disableFacturX();
this.xmlProvider = z1p;
} else if (ver == 2) {
ZUGFeRD2PullProvider z2p = new ZUGFeRD2PullProvider();
@@ -210,11 +211,21 @@ public class ZUGFeRDExporter implements Closeable {
setZUGFeRDVersion(DefaultZUGFeRDVersion);
}
/**
* Factur-X is now set by default since ZF 2.1, you have to disable it if you dont wont it
* Generate ZF2.1 files with filename factur-x.xml
* @deprecated
* */
public void setFacturX() {
setZUGFeRDVersion(2);
isFacturX = true;
}
/***
* Generate ZF2.0/2.1 files with filename zugferd-invoice.xml instead of factur-x.xml
*/
public void disableFacturX() {
isFacturX = false;
}
/**
* All files are PDF/A-3, setConformance refers to the level conformance.
*
@@ -464,6 +475,7 @@ public class ZUGFeRDExporter implements Closeable {
ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile);
// ef.addCompression();
ef.setSubtype(subType);
ef.setSize(data.length);
ef.setCreationDate(new GregorianCalendar());
@@ -583,7 +595,7 @@ public class ZUGFeRDExporter implements Closeable {
protected void addXMP(XMPMetadata metadata) {
if (attachZUGFeRDHeaders) {
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, profile,
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, ZFVersion, isFacturX, profile,
getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion),
getFilenameForVersion(ZFVersion));

View File

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

View File

@@ -0,0 +1,432 @@
/** **********************************************************************
*
* Copyright 2019 Jochen Staerk
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import junit.framework.TestCase;
/***
* This is a test to confirm the minimum steps to implement a interface are still sufficient
*
* @author jstaerk
*
*/
public class BackwardCompatibilityTest extends TestCase implements IZUGFeRDExportableTransaction{
final String TARGET_PDF_ZF1 = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506zf1.pdf";
final String TARGET_PDF_ZF2 = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506zf2.pdf";
final String TARGET_PDF_FX = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506fx.pdf";
/**
* The exporter test bases on @{code
* ./src/test/MustangGnuaccountingBeispielRE-20140703_502blanko.pdf}, adds
* metadata, writes to @{code ./target/testout-*} and then imports to check the
* values. It would not make sense to have it run before the less complex
* importer test (which is probably redundant). As only Name Ascending is
* supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export
*/
public void testZF1Export() {
// the writing part
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(1).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this);
ze.disableAutoClose(true);
ze.export(TARGET_PDF_ZF1);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos);
ze.close();
String pdfContent = baos.toString("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);
// assertFalse(pdfContent.indexOf("<pdfaSchema:prefix>zf</pdfaSchema:prefix>") == -1);
// assertFalse(pdfContent.indexOf("urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#") == -1);
} catch (IOException e) {
fail("IOException should not happen in testZExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_ZF1);
// Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
}
public void testZF2Export() {
// the writing part
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this);
ze.disableAutoClose(true);
ze.export(TARGET_PDF_ZF2);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos);
ze.close();
String pdfContent = baos.toString("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);
// assertFalse(pdfContent.indexOf("<pdfaSchema:prefix>zf</pdfaSchema:prefix>") == -1);
// assertFalse(pdfContent.indexOf("urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#") == -1);
} catch (IOException e) {
fail("IOException should not happen in testZExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_ZF2);
// Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
}
public void testFXExport() {
// the writing part
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) {
ze.setFacturX();
ze.PDFattachZugferdFile(this);
ze.disableAutoClose(true);
ze.export(TARGET_PDF_FX);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos);
ze.close();
String pdfContent = baos.toString("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);
// assertFalse(pdfContent.indexOf("<pdfaSchema:prefix>zf</pdfaSchema:prefix>") == -1);
// assertFalse(pdfContent.indexOf("urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#") == -1);
} catch (IOException e) {
fail("IOException should not happen in testZExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX);
// Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
}
class Contact implements IZUGFeRDExportableContact {
public String getCountry() {
return "DE";
}
public String getLocation() {
return "Spielkreis";
}
public String getName() {
return "Theodor Est";
}
public String getStreet() {
return "Bahnstr. 42";
}
public String getVATID() {
return "DE999999999";
}
public String getZIP() {
return "88802";
}
}
class Payment implements IZUGFeRDTradeSettlementPayment {
@Override
public String getOwnBIC() {
return "bla";
}
@Override
public String getOwnBankName() {
return "bla";
}
@Override
public String getOwnIBAN() {
return "bla";
}
}
class Item implements IZUGFeRDExportableItem {
public Item(BigDecimal price, BigDecimal quantity, Product product) {
super();
this.price = price;
this.quantity = quantity;
this.product = product;
}
private BigDecimal price, quantity;
private Product product;
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public BigDecimal getQuantity() {
return quantity;
}
public void setQuantity(BigDecimal quantity) {
this.quantity = quantity;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public IZUGFeRDAllowanceCharge[] getItemAllowances() {
// TODO Auto-generated method stub
return null;
}
public IZUGFeRDAllowanceCharge[] getItemCharges() {
// TODO Auto-generated method stub
return null;
}
}
class Product implements IZUGFeRDExportableProduct {
public Product(String description, String name, String unit, BigDecimal vATPercent) {
super();
this.description = description;
this.name = name;
this.unit = unit;
VATPercent = vATPercent;
}
private String description, name, unit;
private BigDecimal VATPercent;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public BigDecimal getVATPercent() {
return VATPercent;
}
public void setVATPercent(BigDecimal vATPercent) {
VATPercent = vATPercent;
}
}
@Override
public Date getDeliveryDate() {
return new GregorianCalendar(2019, Calendar.JUNE, 10).getTime();
}
@Override
public IZUGFeRDExportableContact getRecipient() {
return new Contact();
}
//
public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
Payment P = new Payment();
IZUGFeRDTradeSettlementPayment[] allP = new Payment[1];
allP[0] = P;
return allP;
}
public IZUGFeRDAllowanceCharge[] getZFAllowances() {
// TODO Auto-generated method stub
return null;
}
public IZUGFeRDAllowanceCharge[] getZFCharges() {
// TODO Auto-generated method stub
return null;
}
@Override
public IZUGFeRDExportableItem[] getZFItems() {
Item[] allItems = new Item[3];
Product designProduct = new Product("", "Design (hours): Of a sample invoice", "HUR",
new BigDecimal("7.000000"));
Product balloonProduct = new Product("", "Ballons: various colors, ~2000ml", "C62", new BigDecimal("19.000000"));
Product airProduct = new Product("", "Hot air „heiße Luft“ (litres)", "LTR", new BigDecimal("19.000000"));
allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct);
allItems[2] = new Item(new BigDecimal("0.025"), new BigDecimal("800"), airProduct);
return allItems;
}
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
// TODO Auto-generated method stub
return null;
}
@Override
public Date getDueDate() {
return new GregorianCalendar(2019, Calendar.JULY, 1).getTime();
}
@Override
public Date getIssueDate() {
return new GregorianCalendar(2019, Calendar.JUNE, 10).getTime();
}
@Override
public String getNumber() {
return "RE-20190610/507";
}
public String getOwnBIC() {
return "COBADEFFXXX";
}
public String getOwnBankName() {
return "Commerzbank";
}
@Override
public String getOwnCountry() {
return "DE";
}
public String getOwnIBAN() {
return "DE88 2008 0000 0970 3757 00";
}
@Override
public String getOwnLocation() {
return "Stadthausen";
}
@Override
public String getOwnOrganisationFullPlaintextInfo() {
return "Bei Spiel GmbH\n" + "Ecke 12\n" + "12345 Stadthausen\n" + "Geschäftsführer: Max Mustermann";
}
@Override
public String getOwnOrganisationName() {
return "Bei Spiel GmbH";
}
@Override
public String getOwnStreet() {
return "Ecke 12";
}
@Override
public String getOwnTaxID() {
return "22/815/0815/4";
}
@Override
public String getOwnVATID() {
return "DE136695976";
}
@Override
public String getOwnZIP() {
return "12345";
}
}

View File

@@ -32,6 +32,7 @@ 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 {
/**
@@ -51,15 +52,15 @@ public class BaseTest extends TestCase {
}
public void testCorrectDigits() {
assertEquals("0.00", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal(0),2));
assertEquals("-1.10", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.10"),2));
assertEquals("-1.10", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.1"),2));
assertEquals("-1.01", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.01"),2));
assertEquals("20000123.35", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3489"),2));
assertEquals("20000123.34", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3419"),2));
assertEquals("12.00", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("12"),2));
assertEquals("12", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("12"),0));
assertEquals("20000123.342", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3419"),3));
assertEquals("0.00", XMLTools.nDigitFormat(new BigDecimal(0),2));
assertEquals("-1.10", XMLTools.nDigitFormat(new BigDecimal("-1.10"),2));
assertEquals("-1.10", XMLTools.nDigitFormat(new BigDecimal("-1.1"),2));
assertEquals("-1.01", XMLTools.nDigitFormat(new BigDecimal("-1.01"),2));
assertEquals("20000123.35", XMLTools.nDigitFormat(new BigDecimal("20000123.3489"),2));
assertEquals("20000123.34", XMLTools.nDigitFormat(new BigDecimal("20000123.3419"),2));
assertEquals("12.00", XMLTools.nDigitFormat(new BigDecimal("12"),2));
assertEquals("12", XMLTools.nDigitFormat(new BigDecimal("12"),0));
assertEquals("20000123.342", XMLTools.nDigitFormat(new BigDecimal("20000123.3419"),3));
}
}

View File

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

View File

@@ -32,6 +32,7 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran
private IZUGFeRDExportableItem[] zFItems;
private IZUGFeRDExportableContact recipient;
private IZUGFeRDTradeSettlementPayment[] settlementPayments;
private IZUGFeRDDate zfDeliveryDate;
private String ownTaxID;
private String ownVATID;
private String ownOrganisationName;
@@ -149,6 +150,11 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran
return referenceNumber;
}
@Override
public IZUGFeRDDate getZFDeliveryDate() {
return zfDeliveryDate;
}
public IZUGFeRDExportableTransactionImpl setNumber(String number) {
this.number = number;
return this;
@@ -234,6 +240,11 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran
return this;
}
public IZUGFeRDExportableTransactionImpl setZfDeliveryDate(IZUGFeRDDate zfDeliveryDate) {
this.zfDeliveryDate = zfDeliveryDate;
return this;
}
public IZUGFeRDExportableTransactionImpl setCurrency(String currency) {
this.currency = currency;
return this;

View File

@@ -22,6 +22,8 @@ import junit.framework.TestCase;
import java.math.BigDecimal;
import org.mustangproject.ZUGFeRD.MustangReaderTestCase.Item;
public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRDExportableTransaction {
public MustangReaderTestCase(String testName) {
@@ -125,7 +127,7 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
protected class Item implements IZUGFeRDExportableItem {
public Item(BigDecimal price, BigDecimal quantity, Product product) {
public Item(BigDecimal price, BigDecimal quantity, IZUGFeRDExportableProduct product) {
super();
this.price = price;
this.quantity = quantity;
@@ -133,7 +135,12 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
}
private BigDecimal price, quantity;
private Product product;
private IZUGFeRDExportableProduct product;
private String addReference=null;
public String getAdditionalReferencedDocumentID() {
return addReference;
}
@Override
public BigDecimal getPrice() {
@@ -154,11 +161,11 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
}
@Override
public Product getProduct() {
public IZUGFeRDExportableProduct getProduct() {
return product;
}
public void setProduct(Product product) {
public void setProduct(IZUGFeRDExportableProduct product) {
this.product = product;
}
@@ -172,6 +179,15 @@ public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRD
return null;
}
public String getAddReference() {
return addReference;
}
public void setAddReference(String addReference) {
this.addReference = addReference;
}
}
protected class Product implements IZUGFeRDExportableProduct {

View File

@@ -257,7 +257,6 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
" </rsm:SupplyChainTradeTransaction>\n" +
"</rsm:CrossIndustryInvoice>";
zea1.setZUGFeRDXMLData(ownZUGFeRDXML.getBytes("UTF-8"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
zea1.disableAutoClose(true);
zea1.export(TARGET_PDF);
@@ -265,7 +264,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
zea1.close();
String pdfContent = baos.toString("UTF-8");
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
assertFalse(pdfContent.indexOf("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>") == -1);
} catch (IOException e) {
e.printStackTrace();
@@ -276,10 +275,8 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
// Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBLZ(), "41441604");
assertEquals(zi.getBIC(), "COBADEFFXXX");
assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00");
assertEquals(zi.getKTO(), "44421800");
assertEquals(zi.getHolder(), "Bei Spiel GmbH");
assertEquals(zi.getForeignReference(), "RE-20171118/506");
}
@@ -303,6 +300,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
ZUGFeRDExporter zea1 = new ZUGFeRDExporterFromA1Factory()
.setProducer("My Application")
.setCreator("Test")
.setZUGFeRDVersion(1)
.setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.BASIC)
.load(SOURCE_PDF);
/* we have much more information than just in the basic profile (comfort or extended) but it's perfectly valid to provide more information, just not less. */
@@ -460,9 +458,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
// Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), "COBADEFFXXX");
assertEquals(zi.getBLZ(), "41441604");
assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00");
assertEquals(zi.getKTO(), "44421800");
assertEquals(zi.getHolder(), "Bei Spiel GmbH");
assertEquals(zi.getForeignReference(), "RE-20170509/505");
}

View File

@@ -181,9 +181,7 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
// Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
assertEquals(zi.getBLZ(), getTradeSettlementPayment()[0].getOwnBLZ());
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getDueDate(), "20170530");
assertEquals(zi.getForeignReference(), getNumber());
@@ -223,11 +221,9 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
// Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
assertEquals(zi.getBLZ(), getTradeSettlementPayment()[0].getOwnBLZ());
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto());
assertEquals("571.04", zi.getAmount());
assertEquals(getTradeSettlementPayment()[0].getOwnBIC(), zi.getBIC());
assertEquals(getTradeSettlementPayment()[0].getOwnIBAN(), zi.getIBAN());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
try {

View File

@@ -196,13 +196,18 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
// Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBLZ(), getTradeSettlementPayment()[0].getOwnBLZ());
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
assertEquals(zi.getIBAN(),getTradeSettlementPayment()[0].getOwnIBAN());
assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), "RE-20170509/505");
assertEquals(zi.getBankName(), "Commerzbank");
assertEquals(zi.getSellerTradePartyAddress().getCityName(), "Stadthausen");
assertEquals(zi.getSellerTradePartyAddress().getCountryID(), "DE");
assertEquals(zi.getSellerTradePartyAddress().getCountrySubDivisionName(), null);
assertEquals(zi.getSellerTradePartyAddress().getLineOne(), "Ecke 12");
assertEquals(zi.getSellerTradePartyAddress().getLineThree(), null);
assertEquals(zi.getSellerTradePartyAddress().getLineTwo(), null);
assertEquals(zi.getSellerTradePartyAddress().getPostcodeCode(), "12345");
}
public void testForeignImport() {
@@ -381,7 +386,6 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
assertEquals(zi.getReference(), getReferenceNumber());
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
}
@@ -450,7 +454,6 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
}

View File

@@ -27,7 +27,7 @@ import java.util.logging.Logger;
/**
* This test utility class is providing usability functions for test file resources
* 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());

View File

@@ -0,0 +1,332 @@
/** **********************************************************************
*
* Copyright 2019 Jochen Staerk
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import org.mustangproject.ZUGFeRD.MustangReaderTestCase.Item;
import junit.framework.Test;
import junit.framework.TestSuite;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ZF2EdgeTest extends MustangReaderTestCase implements IZUGFeRDExportableTransaction {
final String TARGET_PDF = "./target/testout-ZF2newEdge.pdf";
protected class EdgeProduct implements IZUGFeRDExportableProduct {
private String description, name, unit;
public EdgeProduct(String description, String name, String unit) {
super();
this.description = description;
this.name = name;
this.unit = unit;
}
@Override
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
@Override
public BigDecimal getVATPercent() {
return BigDecimal.ZERO;
}
@Override
public boolean isIntraCommunitySupply() {
return true; // simulate intra community supply
}
}
protected class DebitPayment implements IZUGFeRDTradeSettlementDebit {
@Override
public String getIBAN() {
return "DE540815";
}
@Override
public String getMandate() {
return "DE99XX12345";
}
}
@Override
public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
return null;
}
@Override
public IZUGFeRDTradeSettlement[] getTradeSettlement() {
IZUGFeRDTradeSettlement[] payments = new DebitPayment[1];
payments[0] = new DebitPayment();
return payments;
}
@Override
public Date getDeliveryDate() {
return new GregorianCalendar(2017, Calendar.MAY, 7).getTime();
}
@Override
public Date getDueDate() {
return new GregorianCalendar(2017, Calendar.MAY, 30).getTime();
}
@Override
public Date getIssueDate() {
return new GregorianCalendar(2017, Calendar.MAY, 9).getTime();
}
@Override
public String getNumber() {
return "RE-20170509/505";
}
@Override
public String getOwnCountry() {
return "DE";
}
@Override
public String getOwnLocation() {
return "Stadthausen";
}
@Override
public String getOwnOrganisationName() {
return "Bei Spiel GmbH";
}
@Override
public String getOwnStreet() {
return "Ecke 12";
}
@Override
public IZUGFeRDExportableContact getOwnContact() {
return new SenderContact();
}
@Override
public String getOwnTaxID() {
return "22/815/0815/4";
}
@Override
public String getOwnVATID() {
return "DE136695976";
}
@Override
public String getOwnZIP() {
return "12345";
}
@Override
public IZUGFeRDExportableContact getRecipient() {
return new RecipientContact();
}
@Override
public IZUGFeRDExportableContact getDeliveryAddress() {
return new RecipientContact();
}
@Override
public String getOwnOrganisationFullPlaintextInfo() {
return null;
}
@Override
public String getCurrency() {
return "USD";
}
@Override
public IZUGFeRDExportableItem[] getZFItems() {
Item[] allItems = new Item[3];
EdgeProduct designProduct = new EdgeProduct("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung",
"HUR");
EdgeProduct balloonProduct = new EdgeProduct("", "Bestellerweiterung für E&F Umbau", "C62");// test for issue
// 103
EdgeProduct airProduct = new EdgeProduct("", "Heiße Luft pro Liter", "LTR");
Item design=new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
design.setAddReference("1825");
allItems[0] = design;
allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct);
allItems[2] = new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct);
return allItems;
}
@Override
public String getPaymentTermDescription() {
SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
return "Zahlbar ohne Abzug bis zum " + germanDateFormat.format(getDueDate());
}
@Override
public IZUGFeRDAllowanceCharge[] getZFAllowances() {
return null;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFCharges() {
return null;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
return null;
}
@Override
public String getReferenceNumber() {
return "AB321";
}
/**
* Create the test case
*
* @param testName name of the test case
*/
public ZF2EdgeTest(String testName) {
super(testName);
}
/**
* @return the suite of tests being tested
*/
public static Test suite() {
return new TestSuite(ZF2EdgeTest.class);
}
// //////// TESTS
// //////////////////////////////////////////////////////////////////////////////////////////
/**
* The exporter test bases on @{code
* ./src/test/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf}, adds
* metadata, writes to @{code ./target/testout-*} and then imports to check the
* values.
*/
public void testEdgeExport() {
// the writing part
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_PDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
assertTrue(zi.getUTF8().contains("<ram:TypeCode>59</ram:TypeCode>"));
assertTrue(zi.getUTF8().contains("<ram:ShipToTradeParty>"));
assertTrue(zi.getUTF8().contains("<ram:IBANID>DE540815</ram:IBANID>"));
assertTrue(zi.getUTF8().contains("<ram:DirectDebitMandateID>DE99XX12345</ram:DirectDebitMandateID>"));
assertFalse(zi.getUTF8().contains("<ram:DueDateDateTime>"));
assertFalse(zi.getUTF8().contains("EUR"));
assertTrue(zi.getUTF8().contains("USD"));//currency should be USD, test for #150
// Reading ZUGFeRD
assertEquals("496.00", zi.getAmount());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
try {
assertEquals(zi.getVersion(), 2);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* The exporter test bases on @{code
* ./src/test/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf}, adds
* metadata, writes to @{code ./target/testout-*} and then imports to check the
* values.
*/
public void testOutputStreamExport() {
// the writing part
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(bos);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
}
}
}

View File

@@ -0,0 +1,84 @@
/** **********************************************************************
*
* Copyright 2019 Jochen Staerk
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import junit.framework.TestCase;
import junit.framework.Test;
import junit.framework.TestSuite;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ZF2PushTest extends TestCase {
final String TARGET_PDF = "./target/testout-ZF2Push.pdf";
public void testPushExport() {
// the writing part
String orgname="Test company";
String number="123";
String amountStr="1.00";
BigDecimal amount=new BigDecimal(amountStr);
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(new ZUGFeRD2PushProvider().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setOwnOrganisationName(orgname).setOwnStreet("teststr").setOwnZIP("55232").setOwnLocation("teststadt").setOwnCountry("DE").setOwnTaxID("4711").setOwnVATID("0815").setRecipient(new Contact("Franz Müller", "0177123456", "fmueller@test.com", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number).addItem(new Item(new Product("Testprodukt","","C62",new BigDecimal(0)),amount,new BigDecimal(1.0))));
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_PDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
assertFalse(zi.getUTF8().contains("EUR"));
// Reading ZUGFeRD
assertEquals(amountStr, zi.getAmount());
assertEquals(zi.getHolder(), orgname);
assertEquals(zi.getForeignReference(), number);
try {
assertEquals(zi.getVersion(), 2);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -1,244 +1,244 @@
/** **********************************************************************
*
* Copyright 2019 Jochen Staerk
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ZF2EdgeTest extends MustangReaderTestCase {
final String TARGET_PDF = "./target/testout-ZF2newEdge.pdf";
@Override
public Date getDeliveryDate() {
return new GregorianCalendar(2017, Calendar.MAY, 7).getTime();
}
@Override
public Date getDueDate() {
return new GregorianCalendar(2017, Calendar.MAY, 30).getTime();
}
@Override
public Date getIssueDate() {
return new GregorianCalendar(2017, Calendar.MAY, 9).getTime();
}
@Override
public String getNumber() {
return "RE-20170509/505";
}
@Override
public String getOwnCountry() {
return "DE";
}
@Override
public String getOwnLocation() {
return "Stadthausen";
}
@Override
public String getOwnOrganisationName() {
return "Bei Spiel GmbH";
}
@Override
public String getOwnStreet() {
return "Ecke 12";
}
@Override
public IZUGFeRDExportableContact getOwnContact() {
return new SenderContact();
}
@Override
public String getOwnTaxID() {
return "22/815/0815/4";
}
@Override
public String getOwnVATID() {
return "DE136695976";
}
@Override
public String getOwnZIP() {
return "12345";
}
@Override
public IZUGFeRDExportableContact getRecipient() {
return new RecipientContact();
}
@Override
public String getOwnOrganisationFullPlaintextInfo() {
return null;
}
@Override
public String getCurrency() {
return "EUR";
}
@Override
public IZUGFeRDExportableItem[] getZFItems() {
Item[] allItems = new Item[3];
Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR",
new BigDecimal("7.000000"));
Product balloonProduct = new Product("", "Bestellerweiterung für E&F Umbau", "C62",
new BigDecimal("19.000000"));// test for issue 103
Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000"));
allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct);
allItems[2] = new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct);
return allItems;
}
@Override
public String getPaymentTermDescription() {
SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
return "Zahlbar ohne Abzug bis zum " + germanDateFormat.format(getDueDate());
}
@Override
public IZUGFeRDAllowanceCharge[] getZFAllowances() {
return null;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFCharges() {
return null;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
return null;
}
@Override
public String getReferenceNumber() {
return "AB321";
}
/**
* Create the test case
*
* @param testName name of the test case
*/
public ZF2EdgeTest(String testName) {
super(testName);
}
/**
* @return the suite of tests being tested
*/
public static Test suite() {
return new TestSuite(ZF2EdgeTest.class);
}
// //////// TESTS
// //////////////////////////////////////////////////////////////////////////////////////////
/**
* The exporter test bases on @{code
* ./src/test/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf}, adds
* metadata, writes to @{code ./target/testout-*} and then imports to check the
* values.
*/
public void testEdgeExport() {
// the writing part
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_PDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
// Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
try {
assertEquals(zi.getVersion(), 2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* The exporter test bases on @{code
* ./src/test/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf}, adds
* metadata, writes to @{code ./target/testout-*} and then imports to check the
* values.
*/
public void testOutpuStreamExport() {
// the writing part
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(bos);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
}
}
}
/** **********************************************************************
*
* Copyright 2019 Jochen Staerk
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ZF2Test extends MustangReaderTestCase {
final String TARGET_PDF = "./target/testout-ZF2new.pdf";
@Override
public Date getDeliveryDate() {
return new GregorianCalendar(2017, Calendar.MAY, 7).getTime();
}
@Override
public Date getDueDate() {
return new GregorianCalendar(2017, Calendar.MAY, 30).getTime();
}
@Override
public Date getIssueDate() {
return new GregorianCalendar(2017, Calendar.MAY, 9).getTime();
}
@Override
public String getNumber() {
return "RE-20170509/505";
}
@Override
public String getOwnCountry() {
return "DE";
}
@Override
public String getOwnLocation() {
return "Stadthausen";
}
@Override
public String getOwnOrganisationName() {
return "Bei Spiel GmbH";
}
@Override
public String getOwnStreet() {
return "Ecke 12";
}
@Override
public IZUGFeRDExportableContact getOwnContact() {
return new SenderContact();
}
@Override
public String getOwnTaxID() {
return "22/815/0815/4";
}
@Override
public String getOwnVATID() {
return "DE136695976";
}
@Override
public String getOwnZIP() {
return "12345";
}
@Override
public IZUGFeRDExportableContact getRecipient() {
return new RecipientContact();
}
@Override
public String getOwnOrganisationFullPlaintextInfo() {
return null;
}
@Override
public String getCurrency() {
return "EUR";
}
@Override
public IZUGFeRDExportableItem[] getZFItems() {
Item[] allItems = new Item[3];
Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR",
new BigDecimal("7.000000"));
Product balloonProduct = new Product("", "Bestellerweiterung für E&F Umbau", "C62",
new BigDecimal("19.000000"));// test for issue 103
Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000"));
allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct);
allItems[2] = new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct);
return allItems;
}
@Override
public String getPaymentTermDescription() {
SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
return "Zahlbar ohne Abzug bis zum " + germanDateFormat.format(getDueDate());
}
@Override
public IZUGFeRDAllowanceCharge[] getZFAllowances() {
return null;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFCharges() {
return null;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
return null;
}
@Override
public String getReferenceNumber() {
return "AB321";
}
/**
* Create the test case
*
* @param testName name of the test case
*/
public ZF2Test(String testName) {
super(testName);
}
/**
* @return the suite of tests being tested
*/
public static Test suite() {
return new TestSuite(ZF2Test.class);
}
// //////// TESTS
// //////////////////////////////////////////////////////////////////////////////////////////
/**
* The exporter test bases on @{code
* ./src/test/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf}, adds
* metadata, writes to @{code ./target/testout-*} and then imports to check the
* values.
*/
public void testExport() {
// the writing part
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).ignorePDFAErrors()
.load(SOURCE_PDF)) {
ze.PDFattachZugferdFile(this);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_PDF);
} catch (IOException e) {
fail("IOException should not be raised in testEdgeExport");
}
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
assertTrue(zi.getUTF8().contains("<ram:DueDateDateTime>"));
// Reading ZUGFeRD
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getDocumentCode(),"380");
assertEquals(zi.getReference(),"AB321");
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC());
assertEquals(zi.getIBAN(),getTradeSettlementPayment()[0].getOwnIBAN());
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getForeignReference(), getNumber());
assertEquals(zi.getSellerTradePartyAddress().getPostcodeCode(), "12345");
assertEquals(zi.getSellerTradePartyAddress().getLineOne(), "Ecke 12");
assertEquals(zi.getSellerTradePartyAddress().getLineTwo(), null);
assertEquals(zi.getSellerTradePartyAddress().getLineThree(), null);
assertEquals(zi.getSellerTradePartyAddress().getCountrySubDivisionName(), null);
assertEquals(zi.getSellerTradePartyAddress().getCountryID(), "DE");
assertEquals(zi.getSellerTradePartyAddress().getCityName(), "Stadthausen");
List<org.mustangproject.ZUGFeRD.Item> li = zi.getLineItemList();
assertEquals(zi.getLineItemList().get(0).getId().toString(), "1");
assertEquals(zi.getLineItemList().get(0).product.getBuyerAssignedID(), "");
assertEquals(zi.getLineItemList().get(0).product.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).product.getVATPercent().toString(), "7.00");
assertEquals(zi.getLineItemList().get(0).product.getName(), "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung");
assertEquals(zi.getLineItemList().get(0).product.getDescription(), "");
try {
assertEquals(zi.getVersion(), 2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

View File

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

310
mvnw vendored Executable file
View File

@@ -0,0 +1,310 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

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