Merge branch 'master' into test-fuer-inputstream-validation
This commit is contained in:
2
.github/workflows/maven.yml
vendored
2
.github/workflows/maven.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
- uses: actions/setup-java@v3 # the log states the default ~/.m2/toolchains.xml is being created pointing to the JDK
|
- uses: actions/setup-java@v3 # the log states the default ~/.m2/toolchains.xml is being created pointing to the JDK
|
||||||
with:
|
with:
|
||||||
distribution: 'adopt' # for latest JDKs use temurin https://blog.adoptopenjdk.net/2021/08/goodbye-adoptopenjdk-hello-adoptium/
|
distribution: 'adopt' # for latest JDKs use temurin https://blog.adoptopenjdk.net/2021/08/goodbye-adoptopenjdk-hello-adoptium/
|
||||||
java-version: '8'
|
java-version: '11'
|
||||||
cache: 'maven' #cache/restore any dependencies to improve the workflow execution time
|
cache: 'maven' #cache/restore any dependencies to improve the workflow execution time
|
||||||
- name: Build with Maven
|
- name: Build with Maven
|
||||||
run: mvn -B package --file pom.xml
|
run: mvn -B package --file pom.xml
|
||||||
106
History.md
106
History.md
@@ -1,3 +1,103 @@
|
|||||||
|
2.15.0
|
||||||
|
=======
|
||||||
|
2024-
|
||||||
|
- 435 use invoiceimporter as common technical basis also for zugferdimporter
|
||||||
|
- also import delivery address
|
||||||
|
- 527 metrics raises errors
|
||||||
|
- 517
|
||||||
|
- 518 corrently validate more XRechnung versions
|
||||||
|
- make document charges and allowances serializable
|
||||||
|
|
||||||
|
|
||||||
|
2.14.2
|
||||||
|
=======
|
||||||
|
2024-10-14
|
||||||
|
|
||||||
|
- also parse BICs in InvoiceImporter not only IBANs
|
||||||
|
- #509 CLI currently does not write a logfile
|
||||||
|
- #505 crash after invoking ZUGFeRD2PullProvider
|
||||||
|
- #506 Fix POM missing dependencies
|
||||||
|
|
||||||
|
2.14.1
|
||||||
|
=======
|
||||||
|
2024-10-06
|
||||||
|
|
||||||
|
- #481 also be able to convert XRechnung/UBL to PDF not only CII
|
||||||
|
- #494 Quantity/Price Decimal Places
|
||||||
|
- #391 Runden bei Negativwerten
|
||||||
|
- #491/501 non terminating decimal expansion
|
||||||
|
- upgraded en16931 cen schematron to 1.3.12
|
||||||
|
- #499/500 PDF layout corrections
|
||||||
|
|
||||||
|
2.14.0
|
||||||
|
=======
|
||||||
|
2024-09-22
|
||||||
|
|
||||||
|
- #461 UBL import contacts
|
||||||
|
- #463 add support for BT-33, i.e. Tradeparty description #463
|
||||||
|
- #456 Provide a way to set uriUniversalCommunicationId on the TradeParty using JSON deserialization
|
||||||
|
- #467 Fix test using wrong file
|
||||||
|
- #468 Fix validator dependencies
|
||||||
|
- #469 Enable EN16931 schema validation for XRechnung
|
||||||
|
- #471 Fix LegalOrganisation schemeId
|
||||||
|
- #473 Fix UnsupportedOperationException in buildNotes
|
||||||
|
- #476 Add DesignatedProductClassification for SpecifiedTradeProduct
|
||||||
|
- #482 Fix current validation errors
|
||||||
|
- #423 can no longer add attachments via cli
|
||||||
|
- #465 cli version should also be able to combine PDF/A-3 source
|
||||||
|
- #487 update to zugferd 2.3.0
|
||||||
|
- #472 Fix logging implementation missing in CLI
|
||||||
|
- #479 Re-Formatted and re-organized POMs - Part 2
|
||||||
|
|
||||||
|
|
||||||
|
2.13.0
|
||||||
|
=======
|
||||||
|
2024-08-28
|
||||||
|
|
||||||
|
- Item Attributes and Country of Origin missing on Product. #420
|
||||||
|
- Avoid NullPointerException if dueDate is not set. #441
|
||||||
|
- support reasoncodes #431
|
||||||
|
- Enhance Charges/Allowances with reasonCode. #432
|
||||||
|
- Fix build warnings from editing and building. #415
|
||||||
|
- ZUGFeRDVisualizer.toPDF(): generate PDF/A-3b. #400
|
||||||
|
- allow access to invoice attachments via ZUGFeRDInvoiceImporter zii.getFileAttachmentsPDF()
|
||||||
|
and XML (zii.getFileAttachmentsXML)
|
||||||
|
- No interface for required field CreditorReferenceID #436 and
|
||||||
|
- X-Rechnung direct-debit missing mandatory field BT-90 #370. (langfr)
|
||||||
|
- refactor(ZUGFeRDVisualizer): improve PDF visualization performance #438
|
||||||
|
- product creation without description now possible empty description
|
||||||
|
- filename of embedded file was not xrechnung.xml when using profile xrechnung #452
|
||||||
|
- allow legalorganisation to have a tradingbusinessname #447
|
||||||
|
- JSon deserialization does not work with BankDetails #455
|
||||||
|
- Fix ClassCastException in CLI (Main.java). #451
|
||||||
|
- changed additional references by line from String to List and implemented it on Item #454
|
||||||
|
|
||||||
|
2.12.0
|
||||||
|
=======
|
||||||
|
2024-07-20
|
||||||
|
|
||||||
|
- support pdf export/visualization to PDF, thanks to Heavenfighter #387 allow embedd fonts from jar-file for pdf creation #388
|
||||||
|
- Fix #389: ClassCastException: ZUGFeRDExporterFromA3
|
||||||
|
- jakarta support #372
|
||||||
|
- Upgrade to PDFBox 3 #373
|
||||||
|
- Requires Java 11
|
||||||
|
- #397 Build succeeds but file is unusable on alpine/docker
|
||||||
|
- #392 CLI: action combine: --ignorefileextension to ignore PDF/A input file errors dosen't work
|
||||||
|
- for CLI combine, fx is now default
|
||||||
|
- set profile to XR if XR is imported #395
|
||||||
|
- Powershell compatibility: added --no-additional-attachments command line option for better batch processing:
|
||||||
|
In cmd also --attachments "" worked but in powershell it was hard to figure out that one had to use --attachments '""'
|
||||||
|
- Be able to validate XRechnung/UBL files #337
|
||||||
|
- ph-schematron aktualisiert, logback zugungsten log4j entfernt #402
|
||||||
|
- java.util Logging zugungsten log4j entfernt #407
|
||||||
|
- ZF extended no longer requires deliverydate #411
|
||||||
|
- Return all BankDetails from parsed CII xml. Closes #408.
|
||||||
|
- ubl visualization: do not require ubl namespace prefix #416
|
||||||
|
|
||||||
|
2.11.0
|
||||||
|
=======
|
||||||
|
2024-05-22
|
||||||
|
|
||||||
- EN16931 validation 1.3.12 codelists v11 #357
|
- EN16931 validation 1.3.12 codelists v11 #357
|
||||||
- Fonts removed #358
|
- Fonts removed #358
|
||||||
- xrechnungimporter to read from filename, inputstream
|
- xrechnungimporter to read from filename, inputstream
|
||||||
@@ -6,7 +106,11 @@
|
|||||||
- zugferdimporter to accept xml files
|
- zugferdimporter to accept xml files
|
||||||
- UBL importer to also parse contacts
|
- UBL importer to also parse contacts
|
||||||
- https://github.com/ZUGFeRD/mustangproject/pull/369
|
- https://github.com/ZUGFeRD/mustangproject/pull/369
|
||||||
- upgrade ph-schematron from 6.3.3 to 8
|
- support inputstreams https://github.com/ZUGFeRD/mustangproject/pull/379
|
||||||
|
- #314 ZUGFeRDInvoiceImporter additional constructur
|
||||||
|
- add XML cash discount write support (new class, previously only possible for XRechnung, not ZF Extended, using a manually encoded setPaymentTermDescription)
|
||||||
|
- surrendered to XRechnung 3 compromises, e.g. no longer put gross amount if it does not deviate from net
|
||||||
|
- be able to programmatically access validation messages https://github.com/ZUGFeRD/mustangproject/pull/382
|
||||||
|
|
||||||
2.10.0
|
2.10.0
|
||||||
=======
|
=======
|
||||||
|
|||||||
@@ -1,258 +1,267 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
|
<groupId>org.mustangproject</groupId>
|
||||||
|
<artifactId>core</artifactId>
|
||||||
|
<version>2.15.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.mustangproject</groupId>
|
<groupId>org.mustangproject</groupId>
|
||||||
<artifactId>core</artifactId>
|
<artifactId>Mustang-CLI</artifactId>
|
||||||
<version>2.10.1-SNAPSHOT</version>
|
<name>e-invoices commandline tool, allowing to create(embed), split and validate Factur-X/ZUGFeRD files. Validation
|
||||||
</parent>
|
should also work for XRechnung/CII.
|
||||||
<modelVersion>4.0.0</modelVersion>
|
</name>
|
||||||
<groupId>org.mustangproject</groupId>
|
<packaging>jar</packaging>
|
||||||
<artifactId>Mustang-CLI</artifactId>
|
<version>2.15.0-SNAPSHOT</version>
|
||||||
<name>e-invoices commandline tool, allowing to create(embed), split and validate Factur-X/ZUGFeRD files. Validation should also work for XRechnung/CII. </name>
|
<properties>
|
||||||
<packaging>jar</packaging>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<version>2.10.1-SNAPSHOT</version>
|
<maven.compiler.compilerVersion>11</maven.compiler.compilerVersion>
|
||||||
<properties>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
<maven.compiler.compilerVersion>8</maven.compiler.compilerVersion>
|
</properties>
|
||||||
<maven.compiler.source>8</maven.compiler.source>
|
<dependencies>
|
||||||
<maven.compiler.target>8</maven.compiler.target>
|
<dependency>
|
||||||
</properties>
|
<groupId>org.mustangproject</groupId>
|
||||||
<dependencies>
|
<artifactId>validator</artifactId>
|
||||||
<dependency>
|
<version>2.15.0-SNAPSHOT</version>
|
||||||
<groupId>org.mustangproject</groupId>
|
<!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with
|
||||||
<artifactId>validator</artifactId>
|
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
|
||||||
<version>2.10.1-SNAPSHOT</version>
|
-->
|
||||||
<!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with
|
</dependency>
|
||||||
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
|
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
|
||||||
-->
|
<dependency><!-- apache commons cli to parse command line -->
|
||||||
</dependency>
|
<groupId>commons-cli</groupId>
|
||||||
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
|
<artifactId>commons-cli</artifactId>
|
||||||
<dependency><!-- apache commons cli to parse command line -->
|
<version>1.8.0</version>
|
||||||
<groupId>commons-cli</groupId>
|
</dependency>
|
||||||
<artifactId>commons-cli</artifactId>
|
|
||||||
<version>1.5.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.riversun</groupId>
|
|
||||||
<artifactId>bigdoc</artifactId>
|
|
||||||
<version>0.3.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
|
||||||
<version>5.9.1</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.vintage</groupId>
|
|
||||||
<artifactId>junit-vintage-engine</artifactId>
|
|
||||||
<version>5.9.1</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<!-- for directory validation: -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.xmlunit</groupId>
|
|
||||||
<artifactId>xmlunit-core</artifactId>
|
|
||||||
<version>2.10.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.xmlunit</groupId>
|
|
||||||
<artifactId>xmlunit-assertj</artifactId>
|
|
||||||
<version>2.9.1</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- /directory validation: -->
|
<!-- logging -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.2.13</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-core</artifactId>
|
||||||
|
<version>1.2.13</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<!-- This library is needed so that logback stderr output is sent to, well, stderr, otherwise it lands in stdout -->
|
||||||
|
<groupId>org.codehaus.janino</groupId>
|
||||||
|
<artifactId>janino</artifactId>
|
||||||
|
<version>3.1.7</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>2.0.12</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- end of logging -->
|
||||||
|
|
||||||
</dependencies>
|
<dependency>
|
||||||
<build>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<pluginManagement>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
<plugins>
|
<version>5.10.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.vintage</groupId>
|
||||||
|
<artifactId>junit-vintage-engine</artifactId>
|
||||||
|
<version>5.10.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- for directory validation: -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xmlunit</groupId>
|
||||||
|
<artifactId>xmlunit-core</artifactId>
|
||||||
|
<version>2.10.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xmlunit</groupId>
|
||||||
|
<artifactId>xmlunit-assertj</artifactId>
|
||||||
|
<version>2.10.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- /directory validation: -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.xml.bind</groupId>
|
||||||
|
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||||
|
<version>4.0.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<!-- mvn help:effective-pom will otherwise tell it just defaults
|
||||||
|
to 2.3.2 - which does not release in the maven repo, and neither shows any
|
||||||
|
error message :-( -->
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-release-plugin</artifactId>
|
||||||
|
<version>2.5.3</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<!-- mvn help:effective-pom will otherwise tell it just defaults
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
to 2.3.2 - which does not release in the maven repo, and neither shows any
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
error message :-( -->
|
<configuration>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<runOrder>alphabetical</runOrder>
|
||||||
<artifactId>maven-release-plugin</artifactId>
|
</configuration>
|
||||||
<version>2.5.3</version>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
<!-- allow getImplementationVersion for the pom.xml -->
|
||||||
</pluginManagement>
|
<plugin>
|
||||||
<plugins>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<plugin>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<version>3.4.2</version>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<configuration>
|
||||||
<configuration>
|
<archive>
|
||||||
<runOrder>alphabetical</runOrder>
|
<manifest>
|
||||||
</configuration>
|
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||||
</plugin>
|
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
||||||
<!-- allow getImplementationVersion for the pom.xml -->
|
</manifest>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
|
||||||
<version>3.2.0</version>
|
|
||||||
<configuration>
|
|
||||||
<archive>
|
|
||||||
<manifest>
|
|
||||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
|
||||||
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
|
||||||
</manifest>
|
|
||||||
<manifestSections>
|
|
||||||
<manifestSection>
|
|
||||||
<name>FreeSans.ttf</name>
|
|
||||||
<manifestEntries>
|
|
||||||
<Content-Type>font/ttf</Content-Type>
|
|
||||||
</manifestEntries>
|
|
||||||
</manifestSection>
|
|
||||||
<manifestSection>
|
|
||||||
<name>FreeSerif.ttf</name>
|
|
||||||
<manifestEntries>
|
|
||||||
<Content-Type>application/x-font</Content-Type>
|
|
||||||
</manifestEntries>
|
|
||||||
</manifestSection>
|
|
||||||
<manifestSection>
|
|
||||||
<name>Times-Bold.ttf</name>
|
|
||||||
<manifestEntries>
|
|
||||||
<Content-Type>application/x-font</Content-Type>
|
|
||||||
</manifestEntries>
|
|
||||||
</manifestSection>
|
|
||||||
</manifestSections>
|
|
||||||
|
|
||||||
</archive>
|
</archive>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>2.3.2</version>
|
<version>2.3.2</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
<manifest>
|
<manifest>
|
||||||
<addClasspath>true</addClasspath>
|
<addClasspath>true</addClasspath>
|
||||||
<mainClass>org.mustangproject.commandline.main</mainClass>
|
<mainClass>org.mustangproject.commandline.main</mainClass>
|
||||||
</manifest>
|
</manifest>
|
||||||
</archive>
|
</archive>
|
||||||
<descriptorRefs>
|
<descriptorRefs>
|
||||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
</descriptorRefs>
|
</descriptorRefs>
|
||||||
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
|
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
|
||||||
mvn clean compile assembly:single -->
|
mvn clean compile assembly:single -->
|
||||||
<!-- or whatever version you use -->
|
<!-- or whatever version you use -->
|
||||||
<source>8</source>
|
<source>11</source>
|
||||||
<target>8</target>
|
<target>11</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>2.4.3</version>
|
<version>3.5.3</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<transformers>
|
<transformers>
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
<mainClass>org.mustangproject.commandline.Main</mainClass>
|
<mainClass>org.mustangproject.commandline.Main</mainClass>
|
||||||
</transformer>
|
</transformer>
|
||||||
</transformers>
|
</transformers>
|
||||||
<minimizeJar>false</minimizeJar>
|
<minimizeJar>false</minimizeJar>
|
||||||
<filters>
|
<filters>
|
||||||
<filter>
|
<filter>
|
||||||
<artifact>*:*</artifact>
|
<artifact>*:*</artifact>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>LICENSE</exclude>
|
<exclude>LICENSE</exclude>
|
||||||
<exclude>NOTICE</exclude>
|
<exclude>NOTICE</exclude>
|
||||||
<exclude>META-INF/*.SF</exclude>
|
<exclude>META-INF/*.SF</exclude>
|
||||||
<exclude>META-INF/*.DSA</exclude>
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
<exclude>META-INF/*.RSA</exclude>
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
</filter>
|
</filter>
|
||||||
<filter>
|
<filter>
|
||||||
<artifact>log4j:log4j</artifact>
|
<artifact>log4j:log4j</artifact>
|
||||||
<includes>
|
<includes>
|
||||||
<include>**</include>
|
<include>**</include>
|
||||||
</includes>
|
</includes>
|
||||||
</filter>
|
</filter>
|
||||||
<filter>
|
<filter>
|
||||||
<artifact>commons-logging:commons-logging</artifact>
|
<artifact>commons-logging:commons-logging</artifact>
|
||||||
<includes>
|
<includes>
|
||||||
<include>**</include>
|
<include>**</include>
|
||||||
</includes>
|
</includes>
|
||||||
</filter>
|
</filter>
|
||||||
<filter>
|
<filter>
|
||||||
<artifact>com.sun.xml.bind:jaxb-impl</artifact>
|
<artifact>com.sun.xml.bind:jaxb-impl</artifact>
|
||||||
<includes>
|
<includes>
|
||||||
<include>**</include>
|
<include>**</include>
|
||||||
</includes>
|
</includes>
|
||||||
</filter>
|
</filter>
|
||||||
</filters>
|
</filters>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>shade</goal>
|
<goal>shade</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<artifactSet>
|
<artifactSet>
|
||||||
<excludes />
|
<excludes />
|
||||||
</artifactSet>
|
</artifactSet>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
<profiles>
|
<profiles>
|
||||||
<profile> <!-- enforce building binaries with Java 1.8 for Maven Central, otherwise using them e.g. as jar will
|
<profile> <!-- enforce building binaries with Java 1.8 for Maven Central, otherwise using them e.g. as jar will
|
||||||
throw a version exception, triggered automatically on mvn release:release (hopefully) and requires an according
|
throw a version exception, triggered automatically on mvn release:release (hopefully) and requires an according
|
||||||
~/.m2/toolchains.xml file, @see doc/development_documentation.md -->
|
~/.m2/toolchains.xml file, @see doc/development_documentation.md -->
|
||||||
<id>release-sign-artifacts</id>
|
<id>release-sign-artifacts</id>
|
||||||
<activation>
|
<activation>
|
||||||
<property>
|
<property>
|
||||||
<name>performRelease</name>
|
<name>performRelease</name>
|
||||||
<value>true</value>
|
<value>true</value>
|
||||||
</property>
|
</property>
|
||||||
</activation>
|
</activation>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-toolchains-plugin</artifactId>
|
<artifactId>maven-toolchains-plugin</artifactId>
|
||||||
<version>3.1.0</version>
|
<version>3.1.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>toolchain</goal>
|
<goal>toolchain</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<toolchains>
|
<toolchains>
|
||||||
<jdk>
|
<jdk>
|
||||||
<version>8</version>
|
<version>11</version>
|
||||||
<vendor>adopt</vendor>
|
<vendor>adopt</vendor>
|
||||||
</jdk>
|
</jdk>
|
||||||
</toolchains>
|
</toolchains>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
<name>Apache License, Version 2.0</name>
|
<name>Apache License, Version 2.0</name>
|
||||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||||
<distribution>repo</distribution>
|
<distribution>repo</distribution>
|
||||||
<comments>A business-friendly OSS license</comments>
|
<comments>A business-friendly OSS license</comments>
|
||||||
</license>
|
</license>
|
||||||
</licenses>
|
</licenses>
|
||||||
<developers>
|
<developers>
|
||||||
<developer>
|
<developer>
|
||||||
<name>Jochen Stärk</name>
|
<name>Jochen Stärk</name>
|
||||||
<email>jstaerk@usegroup.de</email>
|
<email>jstaerk@usegroup.de</email>
|
||||||
<roles>
|
<roles>
|
||||||
<role>architect</role>
|
<role>architect</role>
|
||||||
<role>developer</role>
|
<role>developer</role>
|
||||||
</roles>
|
</roles>
|
||||||
</developer>
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -36,64 +36,66 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
private static org.slf4j.Logger LOGGER; // log output
|
private static org.slf4j.Logger LOGGER; // log output
|
||||||
|
|
||||||
private static void printUsage() {
|
private static void printUsage() {
|
||||||
System.err.println(getUsage());
|
System.err.println(getUsage());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getUsage() {
|
private static String getUsage() {
|
||||||
return "Usage: --action metrics|combine|extract|a3only|ubl|validate|validateExpectInvalid|validateExpectValid|visualize [-d,--directory] [-l,--listfromstdin] [-i,--ignore fileextension, PDF/A errors] [--disable-file-logging] | [-h,--help] \r\n"
|
return "Usage: --action metrics|combine|extract|a3only|ubl|validate|validateExpectInvalid|validateExpectValid|visualize [-d,--directory] [-l,--listfromstdin] [-i,--ignore fileextension, PDF/A errors] [--disable-file-logging] | [-h,--help] \r\n"
|
||||||
+ " --action license display open source license and notice\n"
|
+ " --action license display open source license and notice\n"
|
||||||
+ " --action metrics\n"
|
+ " --action metrics\n"
|
||||||
+ " -d, --directory count ZUGFeRD files in directory to be scanned\n"
|
+ " -d, --directory count ZUGFeRD files in directory to be scanned\n"
|
||||||
+ " If it is a directory, it will recurse.\n"
|
+ " If it is a directory, it will recurse.\n"
|
||||||
+ " -l, --listfromstdin count ZUGFeRD files from a list of linefeed separated files on runtime.\n"
|
+ " -l, --listfromstdin count ZUGFeRD files from a list of linefeed separated files on runtime.\n"
|
||||||
+ " It will start once a blank line has been entered.\n" + "\n"
|
+ " It will start once a blank line has been entered.\n" + "\n"
|
||||||
+ " Additional parameter for both count operations\n"
|
+ " Additional parameter for both count operations\n"
|
||||||
+ " [-i, --ignorefileextension] Check for all files (*.*) instead of PDF files only (*.pdf) in metrics, ignore PDF/A input file errors in combine\n"
|
+ " [-i, --ignorefileextension] Check for all files (*.*) instead of PDF files only (*.pdf) in metrics, ignore PDF/A input file errors in combine\n"
|
||||||
+ " [--disable-file-logging] disable logging to file.\n"
|
+ " [--disable-file-logging] disable logging to file.\n"
|
||||||
+ " --action extract extract Factur-X PDF to XML file\n"
|
+ " --action extract extract Factur-X PDF to XML file\n"
|
||||||
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||||
+ " [--source <filename>]: set input PDF file\n"
|
+ " [--source <filename>]: set input PDF file\n"
|
||||||
+ " [--out <filename>]: set output XML file\n"
|
+ " [--out <filename>]: set output XML file\n"
|
||||||
+ " --action a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n"
|
+ " --action a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n"
|
||||||
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||||
+ " [--source <filename>]: set input PDF file\n"
|
+ " [--source <filename>]: set input PDF file\n"
|
||||||
+ " [--out <filename>]: set output PDF file\n"
|
+ " [--out <filename>]: set output PDF file\n"
|
||||||
+ " --action combine combine XML and PDF file to Factur-X PDF file\n"
|
+ " --action combine combine XML and PDF file to Factur-X PDF file\n"
|
||||||
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||||
+ " [--source <filename>]: set input PDF file\n"
|
+ " [--source <filename>]: set input PDF file\n"
|
||||||
+ " [--source-xml <filename>]: set input XML file\n"
|
+ " [--source-xml <filename>]: set input XML file\n"
|
||||||
+ " [--out <filename>]: set output PDF file\n"
|
+ " [--out <filename>]: set output PDF file\n"
|
||||||
+ " [--format <fx|zf|ox|da>]: set Factur-X, ZUGFeRD, Order-X or Cross Industry Despatch Advice\n"
|
+ " [--format <fx|zf|ox|da>]: set Factur-X, ZUGFeRD, Order-X or Cross Industry Despatch Advice\n"
|
||||||
+ " [--version <1|2>]: set ZUGFeRD version\n"
|
+ " [--version <1|2>]: set ZUGFeRD version\n"
|
||||||
+ " [--profile <...>]: set ZUGFeRD profile\n"
|
+ " [--profile <...>]: set ZUGFeRD profile\n"
|
||||||
+ " For ZUGFeRD v1 or Order-X: <B>ASIC, <C>OMFORT or EX<T>ENDED\n"
|
+ " For ZUGFeRD v1 or Order-X: <B>ASIC, <C>OMFORT or EX<T>ENDED\n"
|
||||||
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, <X>Rechnung, EX<T>ENDED\n"
|
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, <X>Rechnung, EX<T>ENDED\n"
|
||||||
+ " [--attachments <filenames>]: list of file attachments (passing a single empty file name prevents prompting)\n"
|
+ " [--attachments <filenames>]: list of file attachments (passing a single empty file name prevents prompting)\n"
|
||||||
+ " --action ubl convert UN/CEFACT 2016b CII XML to UBL XML\n"
|
+ " [--no-additional-attachments]: prevent prompting for attachments\n"
|
||||||
+ " [--source <filename>]: set input XML file\n"
|
+ " --action ubl convert UN/CEFACT 2016b CII XML to UBL XML\n"
|
||||||
+ " [--out <filename>]: set output XML file\n"
|
+ " [--source <filename>]: set input XML file\n"
|
||||||
+ " --action upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n"
|
+ " [--out <filename>]: set output XML file\n"
|
||||||
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
+ " --action upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n"
|
||||||
+ " [--source <filename>]: set input XML ZUGFeRD 1 file\n"
|
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||||
+ " [--out <filename>]: set output XML ZUGFeRD 2 file\n"
|
+ " [--source <filename>]: set input XML ZUGFeRD 1 file\n"
|
||||||
+ " --action validate validate XML or PDF file \n"
|
+ " [--out <filename>]: set output XML ZUGFeRD 2 file\n"
|
||||||
+ " [--no-notices]: refrain from reporting notices\n"
|
+ " --action validate validate XML or PDF file \n"
|
||||||
+ " [--logAppend <text>]: text to be added to log line\n"
|
+ " [--no-notices]: refrain from reporting notices\n"
|
||||||
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
+ " [--logAppend <text>]: text to be added to log line\n"
|
||||||
+ " [--source <filename>]: input PDF or XML file\n"
|
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||||
+ " --action validateExpectInvalid validate directory expecting negative results \n"
|
+ " [--source <filename>]: input PDF or XML file\n"
|
||||||
+ " [--no-notices]: refrain from reporting notices\n"
|
+ " --action validateExpectInvalid validate directory expecting negative results \n"
|
||||||
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
+ " [--no-notices]: refrain from reporting notices\n"
|
||||||
+ " -d, --directory to check recursively\n"
|
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||||
+ " --action validateExpectValid validate directory expecting positive results \n"
|
+ " -d, --directory to check recursively\n"
|
||||||
+ " [--no-notices]: refrain from reporting notices\n"
|
+ " --action validateExpectValid validate directory expecting positive results \n"
|
||||||
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
+ " [--no-notices]: refrain from reporting notices\n"
|
||||||
+ " -d, --directory to check recursively \n"
|
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||||
+ " --action visualize convert XML to HTML \n"
|
+ " -d, --directory to check recursively \n"
|
||||||
+ " [--language <lang>]: set output lang (en, fr or de)\n"
|
+ " --action visualize convert XML to HTML \n"
|
||||||
+ " [--source <filename>]: set input XML file\n"
|
+ " [--language <lang>]: set output lang (en, fr or de)\n"
|
||||||
+ " [--out <filename>]: set output HTML file\n"
|
+ " [--source <filename>]: set input XML file\n"
|
||||||
|
+ " [--out <filename>]: set output HTML file\n"
|
||||||
+ " --action pdf convert XML to PDF \n"
|
+ " --action pdf convert XML to PDF \n"
|
||||||
+ " [--source <filename>]: set input XML file\n"
|
+ " [--source <filename>]: set input XML file\n"
|
||||||
+ " [--out <filename>]: set output PDF file\n"
|
+ " [--out <filename>]: set output PDF file\n"
|
||||||
@@ -330,32 +332,36 @@ public class Main {
|
|||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
try {
|
try {
|
||||||
CommandLine cmd;
|
CommandLine cmd;
|
||||||
CommandLineParser parser = new BasicParser();
|
CommandLineParser parser = new DefaultParser();
|
||||||
|
|
||||||
// create Options object
|
// create Options object
|
||||||
Options options = new Options();
|
Options options = new Options();
|
||||||
|
|
||||||
options.addOption(new Option("h", "help", false, "display usage"));
|
options.addOption(new Option("h", "help", false, "display usage"));
|
||||||
options.addOption(new Option("a", "action", true, "which action to perform"));
|
options.addOption(new Option("a", "action", true, "which action to perform"));
|
||||||
options.addOption(new Option("f", "format", true, "which format to output"));
|
options.addOption(new Option("f", "format", true, "which format to output"));
|
||||||
options.addOption(new Option("", "version", true, "which version of the standard to use"));
|
options.addOption(new Option("version", "version", true, "which version of the standard to use"));
|
||||||
options.addOption(new Option("", "profile", true, "which profile of the standard to use"));
|
options.addOption(new Option("profile", "profile", true, "which profile of the standard to use"));
|
||||||
Option attachmentOpt = new Option("", "attachments", true, "File attachments");
|
options.addOption(new Option("no-additional-attachments", "no-additional-attachments", false, "prevent prompting for attachments"));
|
||||||
|
Option attachmentOpt = new Option("attachments", "attachments", true, "File attachments");
|
||||||
attachmentOpt.setValueSeparator(',');
|
attachmentOpt.setValueSeparator(',');
|
||||||
attachmentOpt.setArgs(Option.UNLIMITED_VALUES);
|
attachmentOpt.setArgs(Option.UNLIMITED_VALUES);
|
||||||
|
|
||||||
options.addOption(attachmentOpt);
|
options.addOption(attachmentOpt);
|
||||||
options.addOption(new Option("", "source",true, "which source file to use"));
|
options.addOption(new Option("source", "source", true, "which source file to use"));
|
||||||
options.addOption(new Option("", "source-xml",true, "which source file to use"));
|
options.addOption(new Option("source-xml", "source-xml", true, "which source file to use"));
|
||||||
options.addOption(new Option("", "language",true, "output language (en, de or fr)"));
|
options.addOption(new Option("language", "language", true, "output language (en, de or fr)"));
|
||||||
options.addOption(new Option("", "out",true, "which output file to write to"));
|
options.addOption(new Option("out", "out", true, "which output file to write to"));
|
||||||
options.addOption(new Option("", "no-notices",false, "suppress non-fatal errors"));
|
options.addOption(new Option("no-notices", "no-notices", false, "suppress non-fatal errors"));
|
||||||
options.addOption(new Option("", "logAppend",true, "freeform text to be appended to log messages"));
|
options.addOption(new Option("logAppend", "logAppend", true, "freeform text to be appended to log messages"));
|
||||||
options.addOption(new Option("", "disable-file-logging", false, "suppress logging to file"));
|
options.addOption(new Option("disable-file-logging", "disable-file-logging", false, "suppress logging to file"));
|
||||||
options.addOption(new Option("d", "directory",true, "which directory to operate on"));
|
options.addOption(new Option("d", "directory", true, "which directory to operate on"));
|
||||||
options.addOption(new Option("i", "ignorefileextension",false, "ignore non-matching file extensions"));
|
options.addOption(new Option("i", "ignorefileextension", false, "ignore non-matching file extensions"));
|
||||||
options.addOption(new Option("l", "listfromstdin",false, "take list of files from commandline"));
|
options.addOption(new Option("l", "listfromstdin", false, "take list of files from commandline"));
|
||||||
boolean optionsRecognized=false;
|
|
||||||
|
boolean optionsRecognized = false;
|
||||||
String action = "";
|
String action = "";
|
||||||
Boolean disableFileLogging = false;
|
|
||||||
|
Boolean disableFileLogging = false;
|
||||||
try {
|
try {
|
||||||
cmd = parser.parse(options, args);
|
cmd = parser.parse(options, args);
|
||||||
|
|
||||||
@@ -364,7 +370,8 @@ public class Main {
|
|||||||
String directoryName = cmd.getOptionValue("directory");
|
String directoryName = cmd.getOptionValue("directory");
|
||||||
Boolean filesFromStdIn = cmd.hasOption("listfromstdin");//((Number)cmdLine.getParsedOptionValue("integer-option")).intValue();
|
Boolean filesFromStdIn = cmd.hasOption("listfromstdin");//((Number)cmdLine.getParsedOptionValue("integer-option")).intValue();
|
||||||
Boolean ignoreFileExt = cmd.hasOption("ignorefileextension");
|
Boolean ignoreFileExt = cmd.hasOption("ignorefileextension");
|
||||||
Boolean helpRequested = cmd.hasOption("help") || ((action!=null)&&(action.equals("help")));
|
Boolean noAttachments = cmd.hasOption("no-additional-attachments");
|
||||||
|
Boolean helpRequested = cmd.hasOption("help") || ((action != null) && (action.equals("help")));
|
||||||
disableFileLogging = cmd.hasOption("disable-file-logging");
|
disableFileLogging = cmd.hasOption("disable-file-logging");
|
||||||
|
|
||||||
String sourceName = cmd.getOptionValue("source");
|
String sourceName = cmd.getOptionValue("source");
|
||||||
@@ -380,14 +387,12 @@ public class Main {
|
|||||||
String[] attachmentFilenames = cmd.hasOption("attachments") ? cmd.getOptionValues("attachments") : null;
|
String[] attachmentFilenames = cmd.hasOption("attachments") ? cmd.getOptionValues("attachments") : null;
|
||||||
|
|
||||||
|
|
||||||
|
ArrayList<FileAttachment> attachments = new ArrayList<>();
|
||||||
|
|
||||||
ArrayList<FileAttachment> attachments=new ArrayList <>();
|
|
||||||
/*
|
/*
|
||||||
setting system property to disable FILE appender and
|
setting system property to disable FILE appender and
|
||||||
suppress creation of files and folders.
|
suppress creation of files and folders.
|
||||||
*/
|
*/
|
||||||
System.setProperty("FILE_APPENDER_ENABLED", ((Boolean)(disableFileLogging==false)).toString());
|
System.setProperty("FILE_APPENDER_ENABLED", ((Boolean) (disableFileLogging == false)).toString());
|
||||||
|
|
||||||
LOGGER = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
|
LOGGER = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
|
||||||
|
|
||||||
@@ -401,7 +406,7 @@ public class Main {
|
|||||||
performMetrics(directoryName, filesFromStdIn, ignoreFileExt);
|
performMetrics(directoryName, filesFromStdIn, ignoreFileExt);
|
||||||
optionsRecognized = true;
|
optionsRecognized = true;
|
||||||
} else if ((action != null) && (action.equals("combine"))) {
|
} else if ((action != null) && (action.equals("combine"))) {
|
||||||
performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile, ignoreFileExt, attachmentFilenames, attachments);
|
performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile, ignoreFileExt, attachmentFilenames, attachments, noAttachments);
|
||||||
optionsRecognized = true;
|
optionsRecognized = true;
|
||||||
} else if ((action != null) && (action.equals("extract"))) {
|
} else if ((action != null) && (action.equals("extract"))) {
|
||||||
performExtract(sourceName, outName);
|
performExtract(sourceName, outName);
|
||||||
@@ -422,7 +427,7 @@ public class Main {
|
|||||||
performUBL(sourceName, outName);
|
performUBL(sourceName, outName);
|
||||||
optionsRecognized = true;
|
optionsRecognized = true;
|
||||||
} else if ((action != null) && (action.equals("validate"))) {
|
} else if ((action != null) && (action.equals("validate"))) {
|
||||||
optionsRecognized = performValidate(sourceName, noNotices != null && noNotices, cmd.getOptionValue("logAppend"));
|
optionsRecognized = performValidate(sourceName, noNotices, cmd.getOptionValue("logAppend"));
|
||||||
} else if ((action != null) && (action.equals("validateExpectValid"))) {
|
} else if ((action != null) && (action.equals("validateExpectValid"))) {
|
||||||
optionsRecognized = performValidateExpect(true, directoryName);
|
optionsRecognized = performValidateExpect(true, directoryName);
|
||||||
} else if ((action != null) && (action.equals("validateExpectInvalid"))) {
|
} else if ((action != null) && (action.equals("validateExpectInvalid"))) {
|
||||||
@@ -439,7 +444,11 @@ public class Main {
|
|||||||
System.exit(2);
|
System.exit(2);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error(e.getMessage(), e);
|
if (LOGGER != null) {
|
||||||
|
LOGGER.error(e.getMessage(), e);
|
||||||
|
} else {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
}
|
||||||
System.exit(-1);
|
System.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,10 +519,11 @@ public class Main {
|
|||||||
ensureFileNotExists(outName);
|
ensureFileNotExists(outName);
|
||||||
|
|
||||||
// All params are good! continue...
|
// All params are good! continue...
|
||||||
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().convertOnly().load(pdfName);
|
try (ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1()) {
|
||||||
|
ze.convertOnly().load(pdfName);
|
||||||
ze.export(outName);
|
ze.export(outName);
|
||||||
System.out.println("Written to " + outName);
|
System.out.println("Written to " + outName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void performExtract(String pdfName, String xmlName) throws IOException {
|
private static void performExtract(String pdfName, String xmlName) throws IOException {
|
||||||
@@ -546,7 +556,7 @@ public class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void performCombine(String pdfName, String xmlName, String outName, String format, String zfVersion,
|
private static void performCombine(String pdfName, String xmlName, String outName, String format, String zfVersion,
|
||||||
String zfProfile, Boolean ignoreInputErrors, String[] attachmentFilenames, ArrayList<FileAttachment> attachments) throws Exception {
|
String zfProfile, Boolean ignoreInputErrors, String[] attachmentFilenames, ArrayList<FileAttachment> attachments, Boolean noAttachments) throws Exception {
|
||||||
/*
|
/*
|
||||||
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
|
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
|
||||||
* .setProducer("toecount") .setCreator(System.getProperty("user.name"))
|
* .setProducer("toecount") .setCreator(System.getProperty("user.name"))
|
||||||
@@ -576,12 +586,14 @@ public class Main {
|
|||||||
|
|
||||||
if (attachmentFilenames == null) {
|
if (attachmentFilenames == null) {
|
||||||
byte attachmentContents[] = null;
|
byte attachmentContents[] = null;
|
||||||
String attachmentFilename, attachmentMime, attachmentDescription;
|
String attachmentFilename, attachmentMime;
|
||||||
attachmentFilename = getFilenameFromUser("Additional file attachments filename (empty for none)", "", "pdf", true, false);
|
if (!noAttachments) {
|
||||||
if (attachmentFilename.length() != 0) {
|
attachmentFilename = getFilenameFromUser("Additional file attachments filename (empty for none)", "", "pdf", true, false);
|
||||||
attachmentContents = Files.readAllBytes(Paths.get(attachmentFilename));
|
if (attachmentFilename.length() != 0) {
|
||||||
attachmentMime = Files.probeContentType(Paths.get(attachmentFilename));
|
attachmentContents = Files.readAllBytes(Paths.get(attachmentFilename));
|
||||||
attachments.add(new FileAttachment(attachmentFilename, attachmentMime, "Data", attachmentContents));
|
attachmentMime = Files.probeContentType(Paths.get(attachmentFilename));
|
||||||
|
attachments.add(new FileAttachment(attachmentFilename, attachmentMime, "Data", attachmentContents));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < attachmentFilenames.length; i++) {
|
for (int i = 0; i < attachmentFilenames.length; i++) {
|
||||||
@@ -597,7 +609,7 @@ public class Main {
|
|||||||
|
|
||||||
if (format == null) {
|
if (format == null) {
|
||||||
try {
|
try {
|
||||||
format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD, ox=Order-X, da=Cross Industry Despatch Advice)", "zf", "fx|zf|ox|da");
|
format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD, ox=Order-X, da=Cross Industry Despatch Advice)", "fx", "fx|zf|ox|da");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error(e.getMessage(), e);
|
LOGGER.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
@@ -607,7 +619,7 @@ public class Main {
|
|||||||
|
|
||||||
if (zfVersion == null) {
|
if (zfVersion == null) {
|
||||||
try {
|
try {
|
||||||
zfVersion = getStringFromUser("Version (1 or 2)", Integer.toString(ZUGFeRDExporterFromA3.DefaultZUGFeRDVersion), "1|2");
|
zfVersion = getStringFromUser("Version (1 or 2)", "1", "1|2");//fx default version is 1
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error(e.getMessage(), e);
|
LOGGER.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
@@ -691,53 +703,49 @@ public class Main {
|
|||||||
IZUGFeRDExporter ze = null;
|
IZUGFeRDExporter ze = null;
|
||||||
// All params are good! continue...
|
// All params are good! continue...
|
||||||
if (format.equals("ox")) {
|
if (format.equals("ox")) {
|
||||||
ze = new OXExporterFromA1().setProducer("Mustang-cli")
|
ze = new OXExporterFromA1();
|
||||||
.setZUGFeRDVersion(zfIntVersion)
|
|
||||||
.setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile);
|
|
||||||
if (ignoreInputErrors) {
|
if (ignoreInputErrors) {
|
||||||
((OXExporterFromA1) ze).ignorePDFAErrors();
|
((OXExporterFromA1) ze).ignorePDFAErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (format.equals("da")) {
|
} else if (format.equals("da")) {
|
||||||
ze = new DXExporterFromA1().setProducer("Mustang-cli")
|
ze = new DXExporterFromA1();
|
||||||
.setZUGFeRDVersion(zfIntVersion)
|
|
||||||
.setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile);
|
|
||||||
|
|
||||||
if (ignoreInputErrors) {
|
if (ignoreInputErrors) {
|
||||||
((DXExporterFromA1) ze).ignorePDFAErrors();
|
((DXExporterFromA1) ze).ignorePDFAErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (format.equals("fx")) {
|
if (format.equals("fx")) {
|
||||||
zfIntVersion=2;// actually we are talking of generation, not version
|
zfIntVersion = 2;// actually we are talking of generation, not version
|
||||||
// so even if someone correctly requested factur-x 1 internally we call it zugferd 2 :-(
|
// so even if someone correctly requested factur-x 1 internally we call it zugferd 2 :-(
|
||||||
}
|
}
|
||||||
ze = new ZUGFeRDExporterFromPDFA().load(pdfName);
|
ze = new ZUGFeRDExporterFromPDFA();
|
||||||
|
|
||||||
ze.setProducer("Mustang-cli")
|
|
||||||
.setZUGFeRDVersion(zfIntVersion)
|
|
||||||
.setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile);
|
|
||||||
if (ignoreInputErrors) {
|
if (ignoreInputErrors) {
|
||||||
((ZUGFeRDExporterFromA1) ze).ignorePDFAErrors();
|
((ZUGFeRDExporterFromPDFA) ze).ignorePDFAErrors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (FileAttachment attachment : attachments) {
|
|
||||||
((ZUGFeRDExporterFromA3) ze).attachFile(attachment.getFilename(), attachment.getData(), attachment.getMimetype(), attachment.getRelation());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ze = ze.load(pdfName);
|
ze.load(pdfName);
|
||||||
|
ze.setProducer("Mustang-cli")
|
||||||
|
.setZUGFeRDVersion(zfIntVersion)
|
||||||
|
.setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile);
|
||||||
|
|
||||||
if (format.equals("zf")) {
|
if (format.equals("zf")) {
|
||||||
ze.disableFacturX();
|
ze.disableFacturX();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (FileAttachment attachment : attachments) {
|
||||||
|
ze.attachFile(attachment.getFilename(), attachment.getData(), attachment.getMimetype(), attachment.getRelation());
|
||||||
|
}
|
||||||
|
|
||||||
ze.setXML(Files.readAllBytes(Paths.get(xmlName)));
|
ze.setXML(Files.readAllBytes(Paths.get(xmlName)));
|
||||||
|
|
||||||
ze.export(outName);
|
ze.export(outName);
|
||||||
System.out.println("Written to " + outName);
|
System.out.println("Written to " + outName);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error(e.getMessage(), e);
|
if (LOGGER != null) {
|
||||||
|
LOGGER.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
System.err.println(e.getMessage());
|
System.err.println(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -837,14 +845,9 @@ public class Main {
|
|||||||
} else {
|
} else {
|
||||||
zvi.toPDF(sourceName, outName);
|
zvi.toPDF(sourceName, outName);
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error(e.getMessage(), e);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
LOGGER.error(e.getMessage(), e);
|
|
||||||
} catch (TransformerException e) {
|
|
||||||
LOGGER.error(e.getMessage(), e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.error(e.getMessage(), e);
|
LOGGER.error(e.getMessage(), e);
|
||||||
|
System.err.println(e.getMessage());
|
||||||
}
|
}
|
||||||
System.out.println("Written to " + outName);
|
System.out.println("Written to " + outName);
|
||||||
|
|
||||||
@@ -871,11 +874,8 @@ public class Main {
|
|||||||
* @throws Exception e.g. if the specified resource does not exist at the specified location
|
* @throws Exception e.g. if the specified resource does not exist at the specified location
|
||||||
*/
|
*/
|
||||||
static public String ExportResource(String resourceName) throws Exception {
|
static public String ExportResource(String resourceName) throws Exception {
|
||||||
InputStream stream = null;
|
|
||||||
OutputStream resStreamOut = null;
|
|
||||||
String jarFolder;
|
String jarFolder;
|
||||||
try {
|
try (InputStream stream = Main.class.getResourceAsStream(resourceName)) {//note that each / is a directory down in the "jar tree" been the jar the root of the tree
|
||||||
stream = Main.class.getResourceAsStream(resourceName);//note that each / is a directory down in the "jar tree" been the jar the root of the tree
|
|
||||||
if (stream == null) {
|
if (stream == null) {
|
||||||
throw new Exception("Cannot get resource \"" + resourceName + "\" from Jar file.");
|
throw new Exception("Cannot get resource \"" + resourceName + "\" from Jar file.");
|
||||||
}
|
}
|
||||||
@@ -883,15 +883,11 @@ public class Main {
|
|||||||
int readBytes;
|
int readBytes;
|
||||||
byte[] buffer = new byte[4096];
|
byte[] buffer = new byte[4096];
|
||||||
jarFolder = System.getProperty("user.dir");
|
jarFolder = System.getProperty("user.dir");
|
||||||
resStreamOut = new FileOutputStream(jarFolder + resourceName);
|
try (FileOutputStream resStreamOut = new FileOutputStream(jarFolder + resourceName)) {
|
||||||
while ((readBytes = stream.read(buffer)) > 0) {
|
while ((readBytes = stream.read(buffer)) > 0) {
|
||||||
resStreamOut.write(buffer, 0, readBytes);
|
resStreamOut.write(buffer, 0, readBytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
|
||||||
throw ex;
|
|
||||||
} finally {
|
|
||||||
stream.close();
|
|
||||||
resStreamOut.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return jarFolder + resourceName;
|
return jarFolder + resourceName;
|
||||||
@@ -913,7 +909,8 @@ public class Main {
|
|||||||
if (fileName == null)
|
if (fileName == null)
|
||||||
return false;
|
return false;
|
||||||
File f = new File(fileName);
|
File f = new File(fileName);
|
||||||
return f.exists();
|
// "exists" also returns true for directories
|
||||||
|
return f.isFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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 org.mustangproject.validator.ZUGFeRDValidator;
|
||||||
|
|
||||||
import static org.xmlunit.assertj.XmlAssert.assertThat;
|
import static org.xmlunit.assertj.XmlAssert.assertThat;
|
||||||
@@ -50,25 +47,23 @@ public class ValidatorFileWalker
|
|||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
String expectedString="valid";
|
String expectedString="valid";
|
||||||
if (!expectValid) {
|
if (!expectValid) {
|
||||||
expectedString="invalid";
|
expectedString="invalid";
|
||||||
}
|
}
|
||||||
if ((attr!=null)&&(attr.isRegularFile())) {
|
if ((attr!=null)&&(attr.isRegularFile())) {
|
||||||
if (matcher.matches(file.getFileName())) {
|
if (matcher.matches(file.getFileName())) {
|
||||||
boolean thisResultValid=true;
|
|
||||||
String thisResultString=" valid";
|
String thisResultString=" valid";
|
||||||
try {
|
try {
|
||||||
assertThat(zul.validate(file.toAbsolutePath().toString())).valueByXPath("/validation/summary/@status")
|
assertThat(zul.validate(file.toAbsolutePath().toString())).valueByXPath("/validation/summary/@status")
|
||||||
.asString()
|
.asString()
|
||||||
.isEqualTo(expectedString);
|
.isEqualTo(expectedString);
|
||||||
|
|
||||||
} catch (AssertionError ae) {
|
} catch (AssertionError ae) {
|
||||||
thisResultValid=false;
|
thisResultString="invalid";
|
||||||
thisResultString="invalid";
|
allValid=false;
|
||||||
allValid=false;
|
}
|
||||||
}
|
LOGGER.info(String.format("\n@%s Testing file %d: %s (%s)", dateFormat.format(date), fileCount++, thisResultString, file));
|
||||||
LOGGER.info(String.format("\n@%s Testing file %d: %s (%s)", dateFormat.format(date), fileCount++, thisResultString, file));
|
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return FileVisitResult.CONTINUE;
|
return FileVisitResult.CONTINUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package org.mustangproject.commandline;
|
package org.mustangproject.commandline;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -10,18 +8,43 @@ import java.nio.file.Paths;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public class CliIT {
|
public class CliIT {
|
||||||
|
|
||||||
|
public static File getResourceAsFile(String resourcePath) {
|
||||||
|
try {
|
||||||
|
InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
|
||||||
|
if (in == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
|
||||||
|
tempFile.deleteOnExit();
|
||||||
|
|
||||||
|
try (FileOutputStream out = new FileOutputStream(tempFile)) {
|
||||||
|
// copy stream
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = in.read(buffer)) != -1) {
|
||||||
|
out.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tempFile;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCii2Ubl() throws Exception {
|
public void testCii2Ubl() throws Exception {
|
||||||
Path output = Paths.get("target/ubl.xml");
|
Path output = Paths.get("target/ubl.xml");
|
||||||
Files.deleteIfExists(output);
|
Files.deleteIfExists(output);
|
||||||
Path jar = Files.newDirectoryStream(Paths.get("target"), "Mustang-CLI-*.jar").iterator().next();
|
Path jar = Files.newDirectoryStream(Paths.get("target"), "Mustang-CLI-*.jar").iterator().next();
|
||||||
ProcessBuilder pb = new ProcessBuilder("java", "-jar", jar.toString(),
|
ProcessBuilder pb = new ProcessBuilder("java", "-jar", jar.toString(),
|
||||||
"--action", "ubl", "--source", "src/test/resources/cii.xml", "--out",
|
"--action", "ubl", "--source", "src/test/resources/cii.xml", "--out",
|
||||||
output.toString());
|
output.toString());
|
||||||
pb.redirectErrorStream(true);
|
pb.redirectErrorStream(true);
|
||||||
Process process = pb.start();
|
Process process = pb.start();
|
||||||
String result = getOutput(process);
|
String result = getOutput(process);
|
||||||
@@ -43,4 +66,17 @@ public class CliIT {
|
|||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMetric() {
|
||||||
|
StatRun sr = new StatRun();
|
||||||
|
File tempFile = getResourceAsFile("corrupt-factur-x-waytoosmall.pdf");
|
||||||
|
|
||||||
|
FileChecker fc = new FileChecker(tempFile.getAbsolutePath(), sr);
|
||||||
|
|
||||||
|
fc.checkForZUGFeRD();
|
||||||
|
System.out.print(fc.getOutputLine());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
%PDF-1.4
|
||||||
|
%ェォャュ
|
||||||
@@ -34,14 +34,11 @@ If you set up a Maven project, you can reference the mustang artifact like this:
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mustangproject</groupId>
|
<groupId>org.mustangproject</groupId>
|
||||||
<artifactId>library</artifactId>
|
<artifactId>library</artifactId>
|
||||||
<version>2.11.0</version>
|
<version>2.14.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
Further docs on how to develop **with** mustang:
|
Further docs on how to develop **with** mustang:
|
||||||
|
|
||||||
- [ZugferdDev.en.pdf](https://github.com/ZUGFeRD/mustangproject/blob/master/doc/ZugferdDev.en.pdf?raw=true): The English mustang user documentation.
|
|
||||||
- [ZugferdDev.de.pdf](https://github.com/ZUGFeRD/mustangproject/blob/master/doc/ZugferdDev.de.pdf?raw=true): The German mustang user documentation.
|
|
||||||
- [Usage examples](https://www.mustangproject.org/use/): Read and write electronic invoices.
|
- [Usage examples](https://www.mustangproject.org/use/): Read and write electronic invoices.
|
||||||
- [Mustang classes](https://www.mustangproject.org/invoice-class/): Using the mustang classes.
|
- [Mustang classes](https://www.mustangproject.org/invoice-class/): Using the mustang classes.
|
||||||
|
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ Additionally, the Mustang validator now also supports XRechnung 2, can now also
|
|||||||
|
|
||||||
|
|
||||||
### Use on command line
|
### Use on command line
|
||||||
`java -jar Mustang-CLI-2.0.0-alpha3.jar --action=combine` embeds a XML into a PDF (A-1) file and exports as PDF/A-3
|
`java -jar Mustang-CLI-2.14.0.jar --action=combine` embeds a XML into a PDF (A-1) file and exports as PDF/A-3
|
||||||
|
|
||||||
`java -jar mustang-cli.jar --action=extract` extracts XML from a ZUGFeRD file and
|
`java -jar Mustang-CLI-2.14.0.jar --action=extract` extracts XML from a ZUGFeRD file and
|
||||||
|
|
||||||
`java -jar mustang-cli.jar --action=validate` validates XML or PDF files.
|
`java -jar Mustang-CLI-2.14.0.jar --action=validate` validates XML or PDF files.
|
||||||
|
|
||||||
`java -jar mustang-cli.jar --help` still outputs the parameters which can be used
|
`java -jar Mustang-CLI-2.14.0.jar --help` still outputs the parameters which can be used
|
||||||
to for non-interactive (i.e., batch) processing.
|
to for non-interactive (i.e., batch) processing.
|
||||||
|
|
||||||
|
|
||||||
@@ -37,12 +37,13 @@ from `-f` (ZUV) to the usual `--source`.
|
|||||||
|
|
||||||
We're now on maven central, please remove the old github repository. Additionally, the following changed
|
We're now on maven central, please remove the old github repository. Additionally, the following changed
|
||||||
|
|
||||||
| What | old value | new value |
|
| What | old value | new value |
|
||||||
|---|---|---|
|
|---|---|--------------------|
|
||||||
| Group id | org.mustangproject.zugferd | org.mustangproject|
|
| Group id | org.mustangproject.zugferd | org.mustangproject |
|
||||||
| Artifact ID | mustang | library |
|
| Artifact ID | mustang | library |
|
||||||
| Version | 1.7.8 | 2.0.0-alpha3 |
|
| Version | 1.7.8 | 2.14.0 |
|
||||||
|
|
||||||
|
And please use the shaded classifier.
|
||||||
If you want you can also embed the validator in your software using validator
|
If you want you can also embed the validator in your software using validator
|
||||||
as artifact ID. "validator" includes the library functionality but is >20 MB
|
as artifact ID. "validator" includes the library functionality but is >20 MB
|
||||||
bigger due to its dependencies.
|
bigger due to its dependencies.
|
||||||
@@ -200,7 +201,7 @@ read/write ZUGFeRD-invoices like the (smaller) library module.
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mustangproject</groupId>
|
<groupId>org.mustangproject</groupId>
|
||||||
<artifactId>validator</artifactId>
|
<artifactId>validator</artifactId>
|
||||||
<version>2.0.0</version>
|
<version>2.14.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@@ -1,373 +0,0 @@
|
|||||||
Mozilla Public License Version 2.0
|
|
||||||
==================================
|
|
||||||
|
|
||||||
1. Definitions
|
|
||||||
--------------
|
|
||||||
|
|
||||||
1.1. "Contributor"
|
|
||||||
means each individual or legal entity that creates, contributes to
|
|
||||||
the creation of, or owns Covered Software.
|
|
||||||
|
|
||||||
1.2. "Contributor Version"
|
|
||||||
means the combination of the Contributions of others (if any) used
|
|
||||||
by a Contributor and that particular Contributor's Contribution.
|
|
||||||
|
|
||||||
1.3. "Contribution"
|
|
||||||
means Covered Software of a particular Contributor.
|
|
||||||
|
|
||||||
1.4. "Covered Software"
|
|
||||||
means Source Code Form to which the initial Contributor has attached
|
|
||||||
the notice in Exhibit A, the Executable Form of such Source Code
|
|
||||||
Form, and Modifications of such Source Code Form, in each case
|
|
||||||
including portions thereof.
|
|
||||||
|
|
||||||
1.5. "Incompatible With Secondary Licenses"
|
|
||||||
means
|
|
||||||
|
|
||||||
(a) that the initial Contributor has attached the notice described
|
|
||||||
in Exhibit B to the Covered Software; or
|
|
||||||
|
|
||||||
(b) that the Covered Software was made available under the terms of
|
|
||||||
version 1.1 or earlier of the License, but not also under the
|
|
||||||
terms of a Secondary License.
|
|
||||||
|
|
||||||
1.6. "Executable Form"
|
|
||||||
means any form of the work other than Source Code Form.
|
|
||||||
|
|
||||||
1.7. "Larger Work"
|
|
||||||
means a work that combines Covered Software with other material, in
|
|
||||||
a separate file or files, that is not Covered Software.
|
|
||||||
|
|
||||||
1.8. "License"
|
|
||||||
means this document.
|
|
||||||
|
|
||||||
1.9. "Licensable"
|
|
||||||
means having the right to grant, to the maximum extent possible,
|
|
||||||
whether at the time of the initial grant or subsequently, any and
|
|
||||||
all of the rights conveyed by this License.
|
|
||||||
|
|
||||||
1.10. "Modifications"
|
|
||||||
means any of the following:
|
|
||||||
|
|
||||||
(a) any file in Source Code Form that results from an addition to,
|
|
||||||
deletion from, or modification of the contents of Covered
|
|
||||||
Software; or
|
|
||||||
|
|
||||||
(b) any new file in Source Code Form that contains any Covered
|
|
||||||
Software.
|
|
||||||
|
|
||||||
1.11. "Patent Claims" of a Contributor
|
|
||||||
means any patent claim(s), including without limitation, method,
|
|
||||||
process, and apparatus claims, in any patent Licensable by such
|
|
||||||
Contributor that would be infringed, but for the grant of the
|
|
||||||
License, by the making, using, selling, offering for sale, having
|
|
||||||
made, import, or transfer of either its Contributions or its
|
|
||||||
Contributor Version.
|
|
||||||
|
|
||||||
1.12. "Secondary License"
|
|
||||||
means either the GNU General Public License, Version 2.0, the GNU
|
|
||||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
|
||||||
Public License, Version 3.0, or any later versions of those
|
|
||||||
licenses.
|
|
||||||
|
|
||||||
1.13. "Source Code Form"
|
|
||||||
means the form of the work preferred for making modifications.
|
|
||||||
|
|
||||||
1.14. "You" (or "Your")
|
|
||||||
means an individual or a legal entity exercising rights under this
|
|
||||||
License. For legal entities, "You" includes any entity that
|
|
||||||
controls, is controlled by, or is under common control with You. For
|
|
||||||
purposes of this definition, "control" means (a) the power, direct
|
|
||||||
or indirect, to cause the direction or management of such entity,
|
|
||||||
whether by contract or otherwise, or (b) ownership of more than
|
|
||||||
fifty percent (50%) of the outstanding shares or beneficial
|
|
||||||
ownership of such entity.
|
|
||||||
|
|
||||||
2. License Grants and Conditions
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
2.1. Grants
|
|
||||||
|
|
||||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
|
||||||
non-exclusive license:
|
|
||||||
|
|
||||||
(a) under intellectual property rights (other than patent or trademark)
|
|
||||||
Licensable by such Contributor to use, reproduce, make available,
|
|
||||||
modify, display, perform, distribute, and otherwise exploit its
|
|
||||||
Contributions, either on an unmodified basis, with Modifications, or
|
|
||||||
as part of a Larger Work; and
|
|
||||||
|
|
||||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
|
||||||
for sale, have made, import, and otherwise transfer either its
|
|
||||||
Contributions or its Contributor Version.
|
|
||||||
|
|
||||||
2.2. Effective Date
|
|
||||||
|
|
||||||
The licenses granted in Section 2.1 with respect to any Contribution
|
|
||||||
become effective for each Contribution on the date the Contributor first
|
|
||||||
distributes such Contribution.
|
|
||||||
|
|
||||||
2.3. Limitations on Grant Scope
|
|
||||||
|
|
||||||
The licenses granted in this Section 2 are the only rights granted under
|
|
||||||
this License. No additional rights or licenses will be implied from the
|
|
||||||
distribution or licensing of Covered Software under this License.
|
|
||||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
|
||||||
Contributor:
|
|
||||||
|
|
||||||
(a) for any code that a Contributor has removed from Covered Software;
|
|
||||||
or
|
|
||||||
|
|
||||||
(b) for infringements caused by: (i) Your and any other third party's
|
|
||||||
modifications of Covered Software, or (ii) the combination of its
|
|
||||||
Contributions with other software (except as part of its Contributor
|
|
||||||
Version); or
|
|
||||||
|
|
||||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
|
||||||
its Contributions.
|
|
||||||
|
|
||||||
This License does not grant any rights in the trademarks, service marks,
|
|
||||||
or logos of any Contributor (except as may be necessary to comply with
|
|
||||||
the notice requirements in Section 3.4).
|
|
||||||
|
|
||||||
2.4. Subsequent Licenses
|
|
||||||
|
|
||||||
No Contributor makes additional grants as a result of Your choice to
|
|
||||||
distribute the Covered Software under a subsequent version of this
|
|
||||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
|
||||||
permitted under the terms of Section 3.3).
|
|
||||||
|
|
||||||
2.5. Representation
|
|
||||||
|
|
||||||
Each Contributor represents that the Contributor believes its
|
|
||||||
Contributions are its original creation(s) or it has sufficient rights
|
|
||||||
to grant the rights to its Contributions conveyed by this License.
|
|
||||||
|
|
||||||
2.6. Fair Use
|
|
||||||
|
|
||||||
This License is not intended to limit any rights You have under
|
|
||||||
applicable copyright doctrines of fair use, fair dealing, or other
|
|
||||||
equivalents.
|
|
||||||
|
|
||||||
2.7. Conditions
|
|
||||||
|
|
||||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
|
||||||
in Section 2.1.
|
|
||||||
|
|
||||||
3. Responsibilities
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
3.1. Distribution of Source Form
|
|
||||||
|
|
||||||
All distribution of Covered Software in Source Code Form, including any
|
|
||||||
Modifications that You create or to which You contribute, must be under
|
|
||||||
the terms of this License. You must inform recipients that the Source
|
|
||||||
Code Form of the Covered Software is governed by the terms of this
|
|
||||||
License, and how they can obtain a copy of this License. You may not
|
|
||||||
attempt to alter or restrict the recipients' rights in the Source Code
|
|
||||||
Form.
|
|
||||||
|
|
||||||
3.2. Distribution of Executable Form
|
|
||||||
|
|
||||||
If You distribute Covered Software in Executable Form then:
|
|
||||||
|
|
||||||
(a) such Covered Software must also be made available in Source Code
|
|
||||||
Form, as described in Section 3.1, and You must inform recipients of
|
|
||||||
the Executable Form how they can obtain a copy of such Source Code
|
|
||||||
Form by reasonable means in a timely manner, at a charge no more
|
|
||||||
than the cost of distribution to the recipient; and
|
|
||||||
|
|
||||||
(b) You may distribute such Executable Form under the terms of this
|
|
||||||
License, or sublicense it under different terms, provided that the
|
|
||||||
license for the Executable Form does not attempt to limit or alter
|
|
||||||
the recipients' rights in the Source Code Form under this License.
|
|
||||||
|
|
||||||
3.3. Distribution of a Larger Work
|
|
||||||
|
|
||||||
You may create and distribute a Larger Work under terms of Your choice,
|
|
||||||
provided that You also comply with the requirements of this License for
|
|
||||||
the Covered Software. If the Larger Work is a combination of Covered
|
|
||||||
Software with a work governed by one or more Secondary Licenses, and the
|
|
||||||
Covered Software is not Incompatible With Secondary Licenses, this
|
|
||||||
License permits You to additionally distribute such Covered Software
|
|
||||||
under the terms of such Secondary License(s), so that the recipient of
|
|
||||||
the Larger Work may, at their option, further distribute the Covered
|
|
||||||
Software under the terms of either this License or such Secondary
|
|
||||||
License(s).
|
|
||||||
|
|
||||||
3.4. Notices
|
|
||||||
|
|
||||||
You may not remove or alter the substance of any license notices
|
|
||||||
(including copyright notices, patent notices, disclaimers of warranty,
|
|
||||||
or limitations of liability) contained within the Source Code Form of
|
|
||||||
the Covered Software, except that You may alter any license notices to
|
|
||||||
the extent required to remedy known factual inaccuracies.
|
|
||||||
|
|
||||||
3.5. Application of Additional Terms
|
|
||||||
|
|
||||||
You may choose to offer, and to charge a fee for, warranty, support,
|
|
||||||
indemnity or liability obligations to one or more recipients of Covered
|
|
||||||
Software. However, You may do so only on Your own behalf, and not on
|
|
||||||
behalf of any Contributor. You must make it absolutely clear that any
|
|
||||||
such warranty, support, indemnity, or liability obligation is offered by
|
|
||||||
You alone, and You hereby agree to indemnify every Contributor for any
|
|
||||||
liability incurred by such Contributor as a result of warranty, support,
|
|
||||||
indemnity or liability terms You offer. You may include additional
|
|
||||||
disclaimers of warranty and limitations of liability specific to any
|
|
||||||
jurisdiction.
|
|
||||||
|
|
||||||
4. Inability to Comply Due to Statute or Regulation
|
|
||||||
---------------------------------------------------
|
|
||||||
|
|
||||||
If it is impossible for You to comply with any of the terms of this
|
|
||||||
License with respect to some or all of the Covered Software due to
|
|
||||||
statute, judicial order, or regulation then You must: (a) comply with
|
|
||||||
the terms of this License to the maximum extent possible; and (b)
|
|
||||||
describe the limitations and the code they affect. Such description must
|
|
||||||
be placed in a text file included with all distributions of the Covered
|
|
||||||
Software under this License. Except to the extent prohibited by statute
|
|
||||||
or regulation, such description must be sufficiently detailed for a
|
|
||||||
recipient of ordinary skill to be able to understand it.
|
|
||||||
|
|
||||||
5. Termination
|
|
||||||
--------------
|
|
||||||
|
|
||||||
5.1. The rights granted under this License will terminate automatically
|
|
||||||
if You fail to comply with any of its terms. However, if You become
|
|
||||||
compliant, then the rights granted under this License from a particular
|
|
||||||
Contributor are reinstated (a) provisionally, unless and until such
|
|
||||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
|
||||||
ongoing basis, if such Contributor fails to notify You of the
|
|
||||||
non-compliance by some reasonable means prior to 60 days after You have
|
|
||||||
come back into compliance. Moreover, Your grants from a particular
|
|
||||||
Contributor are reinstated on an ongoing basis if such Contributor
|
|
||||||
notifies You of the non-compliance by some reasonable means, this is the
|
|
||||||
first time You have received notice of non-compliance with this License
|
|
||||||
from such Contributor, and You become compliant prior to 30 days after
|
|
||||||
Your receipt of the notice.
|
|
||||||
|
|
||||||
5.2. If You initiate litigation against any entity by asserting a patent
|
|
||||||
infringement claim (excluding declaratory judgment actions,
|
|
||||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
|
||||||
directly or indirectly infringes any patent, then the rights granted to
|
|
||||||
You by any and all Contributors for the Covered Software under Section
|
|
||||||
2.1 of this License shall terminate.
|
|
||||||
|
|
||||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
|
||||||
end user license agreements (excluding distributors and resellers) which
|
|
||||||
have been validly granted by You or Your distributors under this License
|
|
||||||
prior to termination shall survive termination.
|
|
||||||
|
|
||||||
************************************************************************
|
|
||||||
* *
|
|
||||||
* 6. Disclaimer of Warranty *
|
|
||||||
* ------------------------- *
|
|
||||||
* *
|
|
||||||
* Covered Software is provided under this License on an "as is" *
|
|
||||||
* basis, without warranty of any kind, either expressed, implied, or *
|
|
||||||
* statutory, including, without limitation, warranties that the *
|
|
||||||
* Covered Software is free of defects, merchantable, fit for a *
|
|
||||||
* particular purpose or non-infringing. The entire risk as to the *
|
|
||||||
* quality and performance of the Covered Software is with You. *
|
|
||||||
* Should any Covered Software prove defective in any respect, You *
|
|
||||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
|
||||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
|
||||||
* essential part of this License. No use of any Covered Software is *
|
|
||||||
* authorized under this License except under this disclaimer. *
|
|
||||||
* *
|
|
||||||
************************************************************************
|
|
||||||
|
|
||||||
************************************************************************
|
|
||||||
* *
|
|
||||||
* 7. Limitation of Liability *
|
|
||||||
* -------------------------- *
|
|
||||||
* *
|
|
||||||
* Under no circumstances and under no legal theory, whether tort *
|
|
||||||
* (including negligence), contract, or otherwise, shall any *
|
|
||||||
* Contributor, or anyone who distributes Covered Software as *
|
|
||||||
* permitted above, be liable to You for any direct, indirect, *
|
|
||||||
* special, incidental, or consequential damages of any character *
|
|
||||||
* including, without limitation, damages for lost profits, loss of *
|
|
||||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
|
||||||
* and all other commercial damages or losses, even if such party *
|
|
||||||
* shall have been informed of the possibility of such damages. This *
|
|
||||||
* limitation of liability shall not apply to liability for death or *
|
|
||||||
* personal injury resulting from such party's negligence to the *
|
|
||||||
* extent applicable law prohibits such limitation. Some *
|
|
||||||
* jurisdictions do not allow the exclusion or limitation of *
|
|
||||||
* incidental or consequential damages, so this exclusion and *
|
|
||||||
* limitation may not apply to You. *
|
|
||||||
* *
|
|
||||||
************************************************************************
|
|
||||||
|
|
||||||
8. Litigation
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Any litigation relating to this License may be brought only in the
|
|
||||||
courts of a jurisdiction where the defendant maintains its principal
|
|
||||||
place of business and such litigation shall be governed by laws of that
|
|
||||||
jurisdiction, without reference to its conflict-of-law provisions.
|
|
||||||
Nothing in this Section shall prevent a party's ability to bring
|
|
||||||
cross-claims or counter-claims.
|
|
||||||
|
|
||||||
9. Miscellaneous
|
|
||||||
----------------
|
|
||||||
|
|
||||||
This License represents the complete agreement concerning the subject
|
|
||||||
matter hereof. If any provision of this License is held to be
|
|
||||||
unenforceable, such provision shall be reformed only to the extent
|
|
||||||
necessary to make it enforceable. Any law or regulation which provides
|
|
||||||
that the language of a contract shall be construed against the drafter
|
|
||||||
shall not be used to construe this License against a Contributor.
|
|
||||||
|
|
||||||
10. Versions of the License
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
10.1. New Versions
|
|
||||||
|
|
||||||
Mozilla Foundation is the license steward. Except as provided in Section
|
|
||||||
10.3, no one other than the license steward has the right to modify or
|
|
||||||
publish new versions of this License. Each version will be given a
|
|
||||||
distinguishing version number.
|
|
||||||
|
|
||||||
10.2. Effect of New Versions
|
|
||||||
|
|
||||||
You may distribute the Covered Software under the terms of the version
|
|
||||||
of the License under which You originally received the Covered Software,
|
|
||||||
or under the terms of any subsequent version published by the license
|
|
||||||
steward.
|
|
||||||
|
|
||||||
10.3. Modified Versions
|
|
||||||
|
|
||||||
If you create software not governed by this License, and you want to
|
|
||||||
create a new license for such software, you may create and use a
|
|
||||||
modified version of this License if you rename the license and remove
|
|
||||||
any references to the name of the license steward (except to note that
|
|
||||||
such modified license differs from this License).
|
|
||||||
|
|
||||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
|
||||||
Licenses
|
|
||||||
|
|
||||||
If You choose to distribute Source Code Form that is Incompatible With
|
|
||||||
Secondary Licenses under the terms of this version of the License, the
|
|
||||||
notice described in Exhibit B of this License must be attached.
|
|
||||||
|
|
||||||
Exhibit A - Source Code Form License Notice
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
If it is not possible or desirable to put the notice in a particular
|
|
||||||
file, then You may include the notice in a location (such as a LICENSE
|
|
||||||
file in a relevant directory) where a recipient would be likely to look
|
|
||||||
for such a notice.
|
|
||||||
|
|
||||||
You may add additional accurate notices of copyright ownership.
|
|
||||||
|
|
||||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
|
||||||
---------------------------------------------------------
|
|
||||||
|
|
||||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
|
||||||
defined by the Mozilla Public License, v. 2.0.
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
= Demo Documentation Component B
|
|
||||||
// URLs
|
|
||||||
:url-project: https://antora.org
|
|
||||||
:url-docs: https://docs.antora.org
|
|
||||||
:url-org: https://gitlab.com/antora
|
|
||||||
:url-group: {url-org}/demo
|
|
||||||
:url-demo-site: https://antora.gitlab.io/demo/docs-site
|
|
||||||
:url-site-readme: {url-group}/docs-site/blob/master/README.adoc
|
|
||||||
:url-opendevise: https://opendevise.com
|
|
||||||
|
|
||||||
Component B is an example of a documentation component.
|
|
||||||
It is used by the {url-demo-site}[Antora Demo site].
|
|
||||||
The playbook and instructions for the Demo site are located in the {url-site-readme}[Demo site playbook project].
|
|
||||||
|
|
||||||
== Resources
|
|
||||||
|
|
||||||
* {url-project}[Antora Project Site]
|
|
||||||
* {url-docs}[Antora Docs]
|
|
||||||
* {url-org}[Antora Repositories]
|
|
||||||
|
|
||||||
== Copyright and License
|
|
||||||
|
|
||||||
Copyright (C) 2017-present by OpenDevise Inc. and the individual contributors to Antora.
|
|
||||||
|
|
||||||
Use of this software is granted under the terms of the https://www.mozilla.org/en-US/MPL/2.0/[Mozilla Public License Version 2.0] (MPL-2.0).
|
|
||||||
See link:LICENSE[] to find the full license text.
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# This file represents "software".
|
|
||||||
# This file helps show that documentation files can be in the same repository as software.
|
|
||||||
|
|
||||||
rescue => ex
|
|
||||||
begin
|
|
||||||
context = %(asciidoctor: FAILED: #{attrs['docfile'] || '<stdin>'}: Failed to load AsciiDoc document)
|
|
||||||
if ex.respond_to? :exception
|
|
||||||
# The original message must be explicitely preserved when wrapping a Ruby exception
|
|
||||||
wrapped_ex = ex.exception %(#{context} - #{ex.message})
|
|
||||||
# JRuby automatically sets backtrace, but not MRI
|
|
||||||
wrapped_ex.set_backtrace ex.backtrace
|
|
||||||
else
|
|
||||||
# Likely a Java exception class
|
|
||||||
wrapped_ex = ex.class.new context, ex
|
|
||||||
wrapped_ex.stack_trace = ex.stack_trace
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
wrapped_ex = ex
|
|
||||||
end
|
|
||||||
raise wrapped_ex
|
|
||||||
end
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
name: mustang
|
|
||||||
title: Mustang Library
|
|
||||||
version: 2.6.1
|
|
||||||
prerelease: -beta.1
|
|
||||||
nav:
|
|
||||||
- modules/ROOT/nav.adoc
|
|
||||||
- modules/module-one/nav.adoc
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
* xref:index.adoc[]
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
= Welcome to Component B!
|
|
||||||
:navtitle: Welcome
|
|
||||||
|
|
||||||
This is the automatic start page for version *{page-component-display-version}* of Component B.
|
|
||||||
|
|
||||||
Component B is one of two documentation components in the Antora Demo.
|
|
||||||
The other docs component, Component A, can be accessed using the component selector menu (aka component drawer) at the bottom of the menu on the left side of the page.
|
|
||||||
|
|
||||||
== Page source
|
|
||||||
|
|
||||||
This page is sourced from the AsciiDoc file named [.path]_index.adoc_ that is located at [.path]_demo-component-b/docs/modules/ROOT/pages_.
|
|
||||||
|
|
||||||
=== Why is this the home page of Component B?
|
|
||||||
|
|
||||||
This page is automatically used as the start page of Component B because it is stored in the ROOT module and named [.path]_index.adoc_.
|
|
||||||
|
|
||||||
=== Why is this the home page of the Antora Demo site?
|
|
||||||
|
|
||||||
This page is used as the home page for the Antora Demo because it is assigned as the site `start_page` in the Demo site's playbook file [.path]_site.yml_.
|
|
||||||
|
|
||||||
== Cross reference syntax to target this page
|
|
||||||
|
|
||||||
To create a cross reference *to this page from another page in the ROOT module of Component B*, the xref syntax would be `\xref:index.adoc[]`.
|
|
||||||
|
|
||||||
To create a cross reference *to this page from a page in Module One of Component B*, the xref syntax would be `\xref:ROOT:index.adoc[]`.
|
|
||||||
|
|
||||||
=== Always target the latest version of this page
|
|
||||||
|
|
||||||
To create a cross reference *to the latest version of this page from a page in Component A*, the xref syntax would be `\xref:component-b::index.adoc[]`.
|
|
||||||
|
|
||||||
=== Target a specific version of this page
|
|
||||||
|
|
||||||
To create a cross reference *to version 1.0 of this page from a page in Component A*, the xref syntax would be `\xref:1.0@component-b::index.adoc[]`.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
* xref:overview.adoc[]
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
= Module One Overview
|
|
||||||
|
|
||||||
This is version *{page-component-display-version}* of Module One in Component B.
|
|
||||||
|
|
||||||
== Page source
|
|
||||||
|
|
||||||
This page is sourced from [.path]_demo-component-b/docs/modules/module-one/pages/overview.adoc_.
|
|
||||||
|
|
||||||
== Cross reference syntax to target this page
|
|
||||||
|
|
||||||
To create a cross reference *to this page from another page in Module One*, the xref syntax would be `\xref:overview.adoc[]`.
|
|
||||||
|
|
||||||
To create a cross reference *to this page from a page in the ROOT module of Component B*, the xref syntax would be `\xref:module-one:overview.adoc[]`.
|
|
||||||
|
|
||||||
=== Always target the latest version of this page
|
|
||||||
|
|
||||||
To create a cross reference *to the latest version of this page from a page in Component A*, the xref syntax would be `\xref:component-b:module-one:overview.adoc[]`.
|
|
||||||
|
|
||||||
=== Target a specific version of this page
|
|
||||||
|
|
||||||
To create a cross reference *to version 1.0 of this page from a page in Component A*, the xref syntax would be `\xref:1.0@component-b:module-one:overview.adoc[]`.
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
|
|
||||||
## General approach
|
## Typical process
|
||||||
|
|
||||||
1. build
|
1. build
|
||||||
|
|
||||||
To check if the necessary tools are there, the build is in a stable state and works on your platform, e.g. download and extract https://github.com/ZUGFeRD/mustangproject/archive/master.zip and run ./mvnw clean package
|
To check if the necessary tools are there, the build is in a stable state and works on your platform, e.g. download and extract https://github.com/ZUGFeRD/mustangproject/archive/master.zip and run ./mvnw clean package
|
||||||
|
|
||||||
Mvnw is a maven wrapper which will download maven.Maven is the dependency management tool which will download all libraries, their dependencies, and build the whole thing.
|
|
||||||
Mvnw is a maven wrapper which will download maven.Maven is the dependency management tool which will download all libraries, their dependencies, and build the whole thing.
|
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
|
You will need a Java JDK, e.g. https://www.azul.com/downloads/zulu-community/?architecture=x86-64-bit&package=jdk
|
||||||
@@ -29,6 +28,18 @@ If you do a pull request, please do a feature branch, e.g. if you are working on
|
|||||||
Most of mustang is a library, adding (autmated junit) test cases is often not only the most sustainable but also the fastest way to see if new/changed functionality works. If something is changed so that old test cases break on purpose please do not just remove them but take the time to fix the test cases
|
Most of mustang is a library, adding (autmated junit) test cases is often not only the most sustainable but also the fastest way to see if new/changed functionality works. If something is changed so that old test cases break on purpose please do not just remove them but take the time to fix the test cases
|
||||||
|
|
||||||
|
|
||||||
|
## Typical workflow
|
||||||
|
|
||||||
|
If e.g. new elements or attributes are added, they are often added
|
||||||
|
* in the object so that a developer can use them
|
||||||
|
* in the interface so that a old fashioned developer could use them as well
|
||||||
|
* in the pullprovider so that it actually finds it's way into the XML
|
||||||
|
* in at least one test (the ...edgeTest are supposed to handle edge cases, ~all bells and whistles, maybe it fits there), after the test has been run this should at least once be
|
||||||
|
* validated. If that works one can start implementing the
|
||||||
|
* reading part (along with tests), then it needs to be
|
||||||
|
* documented e.g. on the homepage and
|
||||||
|
* communicated, at the very least by mentioning it in the history.md
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
Mustang contains a library to read/write e-invoices,
|
Mustang contains a library to read/write e-invoices,
|
||||||
@@ -48,7 +59,7 @@ to validate the XML part of the invoices.
|
|||||||
|
|
||||||
## New build
|
## New build
|
||||||
|
|
||||||
Target platform is java 1.8
|
Target platform is java 1.17
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
@@ -115,14 +126,10 @@ The whole settings.xml then looks e.g. like this
|
|||||||
<offline/>
|
<offline/>
|
||||||
<pluginGroups/>
|
<pluginGroups/>
|
||||||
<servers>
|
<servers>
|
||||||
<server>
|
|
||||||
<id>github</id>
|
|
||||||
<password>TOKEN</password>
|
|
||||||
</server>
|
|
||||||
<server>
|
<server>
|
||||||
<id>ossrh</id>
|
<id>ossrh</id>
|
||||||
<username>jstaerk</username>
|
<username>SONATYPE TOKEN USER</username>
|
||||||
<password>JIRA-PASSWORD</password>
|
<password>SONATYPE TOKEN PASSWORD</password>
|
||||||
</server>
|
</server>
|
||||||
|
|
||||||
</servers>
|
</servers>
|
||||||
@@ -150,21 +157,21 @@ Sign in in GitHub and click on the profile picture -> Settings. Now just generat
|
|||||||

|

|
||||||
The Token-ID is the password.
|
The Token-ID is the password.
|
||||||
|
|
||||||
In .m2 also need a toolchains.xml which defines a Sun JDK 1.8 target like the following:
|
In .m2 also need a toolchains.xml which defines a JDK 1.11 target like the following:
|
||||||
```xml
|
```xml
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<toolchains>
|
<toolchains>
|
||||||
<!-- JDK toolchains -->
|
<!-- JDK toolchains -->
|
||||||
<toolchain>
|
<toolchain>
|
||||||
<type>jdk</type>
|
<type>jdk</type>
|
||||||
<provides>
|
<provides>
|
||||||
<version>8</version>
|
<version>11</version>
|
||||||
<vendor>adopt</vendor>
|
<vendor>adopt</vendor>
|
||||||
</provides>
|
</provides>
|
||||||
<configuration>
|
<configuration>
|
||||||
<jdkHome>C:\Program Files\Eclipse Adoptium\jdk-8.0.352.8-hotspot</jdkHome>
|
<jdkHome>C:\Program Files\Eclipse Adoptium\jdk-11.0.23.9-hotspot</jdkHome>
|
||||||
</configuration>
|
</configuration>
|
||||||
</toolchain>
|
</toolchain>
|
||||||
|
|
||||||
</toolchains>
|
</toolchains>
|
||||||
```
|
```
|
||||||
@@ -177,11 +184,11 @@ maybe not yet even existing new release version:
|
|||||||
|
|
||||||
```
|
```
|
||||||
cd validator/target
|
cd validator/target
|
||||||
mvn install:install-file -Dfile=validator-2.5.5-SNAPSHOT-shaded.jar -DgroupId=org.mustangproject -DartifactId=validator -Dversion=2.5.5 -Dpackaging=jar -DgeneratePom=true
|
mvn install:install-file -Dfile=validator-2.12.0-SNAPSHOT-shaded.jar -Dclassifier=shaded -DgroupId=org.mustangproject -DartifactId=validator -Dversion=2.12.0 -Dpackaging=jar -DgeneratePom=true
|
||||||
```
|
```
|
||||||
In gradle you can use something like
|
In gradle you can use something like
|
||||||
```
|
```
|
||||||
implementation files('libs/validator-2.5.6-shaded.jar')
|
implementation files('libs/validator-2.12.0-shaded.jar')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -222,3 +229,47 @@ extract, rename xsl file to xslt, move to new version dir and add a if where the
|
|||||||
* freshcode.club
|
* freshcode.club
|
||||||
* Submit on openpr.de/.com, https://www.einpresswire.com/
|
* Submit on openpr.de/.com, https://www.einpresswire.com/
|
||||||
|
|
||||||
|
## Tips&Inspriration
|
||||||
|
|
||||||
|
|
||||||
|
NodeList from a XPath https://github.com/ZUGFeRD/mustangproject/pull/476/files
|
||||||
|
```
|
||||||
|
xpr = xpath.compile("//*[local-name()=\"PrepaidAmount\"]");
|
||||||
|
NodeList prepaidNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
nodeMap.getNode("GlobalID").ifPresent(idNode -> {
|
||||||
|
if (idNode.hasAttributes()
|
||||||
|
&& idNode.getAttributes().getNamedItem("schemeID") != null) {
|
||||||
|
globalId = new SchemedID()
|
||||||
|
.setScheme(idNode.getAttributes().getNamedItem("schemeID").getNodeValue())
|
||||||
|
.setId(idNode.getTextContent());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
nodeMap.getAsNodeMap and nodeMap.getAsString
|
||||||
|
```
|
||||||
|
|
||||||
|
nodeMap.getAsString("SellerAssignedID").ifPresent(this::setSellerAssignedID);
|
||||||
|
nodeMap.getAsString("BuyerAssignedID").ifPresent(this::setBuyerAssignedID);
|
||||||
|
nodeMap.getAsString("Name").ifPresent(this::setName);
|
||||||
|
nodeMap.getAsString("Description").ifPresent(this::setDescription);
|
||||||
|
|
||||||
|
nodeMap.getAsNodeMap("ApplicableProductCharacteristic").ifPresent(apcNodes -> {
|
||||||
|
String key = apcNodes.getAsStringOrNull("Description");
|
||||||
|
String value = apcNodes.getAsStringOrNull("Value");
|
||||||
|
if (key != null && value != null) {
|
||||||
|
if (attributes == null) {
|
||||||
|
attributes = new HashMap<>();
|
||||||
|
}
|
||||||
|
attributes.put(key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nodeMap.getAsNodeMap("DesignatedProductClassification").ifPresent(dpcNodes -> {
|
||||||
|
String className = dpcNodes.getAsStringOrNull("ClassName");
|
||||||
|
dpcNodes.getNode("ClassCode").map(ClassCode::fromNode).ifPresent(classCode ->
|
||||||
|
classifications.add(new DesignatedProductClassification(classCode, className)));
|
||||||
|
});
|
||||||
|
|
||||||
|
nodeMap.getAsString("OriginTradeCounty").ifPresent(this::setCountryOfOrigin);
|
||||||
|
```
|
||||||
|
|||||||
183
doc/mustang-validation.xsd
Normal file
183
doc/mustang-validation.xsd
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
|
||||||
|
<xs:element name="validation">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element ref="pdf"/>
|
||||||
|
<xs:element ref="messages"/>
|
||||||
|
<xs:element ref="summary"/>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="datetime" use="required"/>
|
||||||
|
<xs:attribute name="filename" use="required" type="xs:NCName"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="pdf">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element ref="report"/>
|
||||||
|
<xs:element ref="info"/>
|
||||||
|
<xs:element ref="messages"/>
|
||||||
|
<xs:element ref="summary"/>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="report">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element ref="buildInformation"/>
|
||||||
|
<xs:element ref="jobs"/>
|
||||||
|
<xs:element ref="batchSummary"/>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="buildInformation">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element maxOccurs="unbounded" ref="releaseDetails"/>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="releaseDetails">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:attribute name="buildDate" use="required" type="xs:dateTime"/>
|
||||||
|
<xs:attribute name="id" use="required" type="xs:NCName"/>
|
||||||
|
<xs:attribute name="version" use="required" type="xs:NMTOKEN"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="jobs">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element ref="job"/>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="job">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element ref="item"/>
|
||||||
|
<xs:element ref="validationReport"/>
|
||||||
|
<xs:element ref="duration"/>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="item">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element ref="name"/>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="size" use="required" type="xs:integer"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="name" type="xs:string"/>
|
||||||
|
<xs:element name="validationReport">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element ref="details"/>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="isCompliant" use="required" type="xs:boolean"/>
|
||||||
|
<xs:attribute name="profileName" use="required"/>
|
||||||
|
<xs:attribute name="statement" use="required"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="details">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:attribute name="failedChecks" use="required" type="xs:integer"/>
|
||||||
|
<xs:attribute name="failedRules" use="required" type="xs:integer"/>
|
||||||
|
<xs:attribute name="passedChecks" use="required" type="xs:integer"/>
|
||||||
|
<xs:attribute name="passedRules" use="required" type="xs:integer"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="batchSummary">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element ref="validationReports"/>
|
||||||
|
<xs:element ref="featureReports"/>
|
||||||
|
<xs:element ref="repairReports"/>
|
||||||
|
<xs:element ref="duration"/>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="encrypted" use="required" type="xs:integer"/>
|
||||||
|
<xs:attribute name="failedToParse" use="required" type="xs:integer"/>
|
||||||
|
<xs:attribute name="outOfMemory" use="required" type="xs:integer"/>
|
||||||
|
<xs:attribute name="totalJobs" use="required" type="xs:integer"/>
|
||||||
|
<xs:attribute name="veraExceptions" use="required" type="xs:integer"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="validationReports">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:integer">
|
||||||
|
<xs:attribute name="compliant" use="required" type="xs:integer"/>
|
||||||
|
<xs:attribute name="failedJobs" use="required" type="xs:integer"/>
|
||||||
|
<xs:attribute name="nonCompliant" use="required" type="xs:integer"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="featureReports">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:integer">
|
||||||
|
<xs:attribute name="failedJobs" use="required" type="xs:integer"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="repairReports">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:integer">
|
||||||
|
<xs:attribute name="failedJobs" use="required" type="xs:integer"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="info">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element ref="signature"/>
|
||||||
|
<xs:element ref="duration"/>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="signature" type="xs:NCName"/>
|
||||||
|
<xs:element name="duration">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:NMTOKEN">
|
||||||
|
<xs:attribute name="finish" type="xs:integer"/>
|
||||||
|
<xs:attribute name="start" type="xs:integer"/>
|
||||||
|
<xs:attribute name="unit" type="xs:NCName"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="messages">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:choice>
|
||||||
|
<xs:element ref="exception"/>
|
||||||
|
<xs:element minOccurs="0" maxOccurs="unbounded" ref="error"/>
|
||||||
|
<xs:element minOccurs="0" maxOccurs="unbounded" ref="notice"/>
|
||||||
|
</xs:choice>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="exception">
|
||||||
|
<xs:complexType mixed="true">
|
||||||
|
<xs:attribute name="type" use="required" type="xs:integer"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="error">
|
||||||
|
<xs:complexType mixed="true">
|
||||||
|
<xs:attribute name="type" use="required" type="xs:integer"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="notice">
|
||||||
|
<xs:complexType mixed="true">
|
||||||
|
<xs:attribute name="type" use="required" type="xs:integer"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="summary">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:attribute name="status" use="required" type="xs:NCName"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:schema>
|
||||||
652
library/pom.xml
652
library/pom.xml
@@ -1,345 +1,341 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
|
<groupId>org.mustangproject</groupId>
|
||||||
|
<artifactId>core</artifactId>
|
||||||
|
<version>2.15.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.mustangproject</groupId>
|
<groupId>org.mustangproject</groupId>
|
||||||
<artifactId>core</artifactId>
|
<artifactId>library</artifactId>
|
||||||
<version>2.10.1-SNAPSHOT</version>
|
<version>2.15.0-SNAPSHOT</version>
|
||||||
</parent>
|
<packaging>jar</packaging>
|
||||||
|
<name>Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII)</name>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<description>FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT
|
||||||
<groupId>org.mustangproject</groupId>
|
Cross Industry Invoice based formats Factur-X/ZUGFeRD, XRechnung and Order-X in your invoice PDFs.
|
||||||
<artifactId>library</artifactId>
|
|
||||||
<version>2.10.1-SNAPSHOT</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<name>Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII)</name>
|
|
||||||
<description>FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT Cross Industry Invoice based formats Factur-X/ZUGFeRD, XRechnung and Order-X in your invoice PDFs.
|
|
||||||
</description>
|
</description>
|
||||||
<url>http://www.mustangproject.org/</url>
|
<url>http://www.mustangproject.org/</url>
|
||||||
<scm>
|
<scm>
|
||||||
<connection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</connection>
|
<connection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</connection>
|
||||||
<developerConnection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</developerConnection>
|
<developerConnection>scm:git:https://github.com/ZUGFeRD/mustangproject.git</developerConnection>
|
||||||
<url>https://github.com/ZUGFeRD/mustangproject</url>
|
<url>https://github.com/ZUGFeRD/mustangproject</url>
|
||||||
<tag>core-2.3.2</tag>
|
<tag>core-2.3.2</tag>
|
||||||
</scm>
|
</scm>
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository><!-- for jargs -->
|
<repository><!-- for jargs -->
|
||||||
<id>sonatype-oss-public</id>
|
<id>sonatype-oss-public</id>
|
||||||
<url>https://oss.sonatype.org/content/groups/public/</url>
|
<url>https://oss.sonatype.org/content/groups/public/</url>
|
||||||
<releases>
|
<releases>
|
||||||
<enabled>true</enabled>
|
<enabled>true</enabled>
|
||||||
</releases>
|
</releases>
|
||||||
<snapshots>
|
<snapshots>
|
||||||
<enabled>true</enabled>
|
<enabled>true</enabled>
|
||||||
</snapshots>
|
</snapshots>
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
<repository>
|
<repository>
|
||||||
<id>internal.repo</id>
|
<id>internal.repo</id>
|
||||||
<name>Temporary Staging Repository</name>
|
<name>Temporary Staging Repository</name>
|
||||||
<url>file://${project.build.directory}/mvn-repo</url>
|
<url>file://${project.build.directory}/mvn-repo</url>
|
||||||
</repository>
|
</repository>
|
||||||
</distributionManagement>
|
</distributionManagement>
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<github.global.server>github</github.global.server>
|
<github.global.server>github</github.global.server>
|
||||||
<additionalparam>-Xdoclint:none</additionalparam>
|
<additionalparam>-Xdoclint:none</additionalparam>
|
||||||
<!-- Skip error check for javadoc -->
|
<!-- Skip error check for javadoc -->
|
||||||
<maven.compiler.compilerVersion>8</maven.compiler.compilerVersion>
|
<maven.compiler.compilerVersion>11</maven.compiler.compilerVersion>
|
||||||
<maven.compiler.source>8</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<maven.compiler.target>8</maven.compiler.target>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
<maven.deploy.skip>true</maven.deploy.skip><!-- do deploy to maven central, parent project does not and inherits -->
|
<maven.deploy.skip>true
|
||||||
|
</maven.deploy.skip><!-- do deploy to maven central, parent project does not and inherits -->
|
||||||
|
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE -->
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.slf4j</groupId>
|
||||||
<groupId>net.sf.saxon</groupId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
<artifactId>Saxon-HE</artifactId>
|
<version>2.0.9</version>
|
||||||
<version>9.9.0-1</version>
|
</dependency>
|
||||||
</dependency><!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
|
<!-- https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>net.sf.saxon</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>Saxon-HE</artifactId>
|
||||||
<version>2.14.2</version>
|
<version>12.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/fop -->
|
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.xmlgraphics</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>fop</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
<version>2.9</version>
|
<version>2.17.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/fop -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.activation</groupId>
|
<groupId>org.apache.xmlgraphics</groupId>
|
||||||
<artifactId>activation</artifactId>
|
<artifactId>fop</artifactId>
|
||||||
<version>1.1.1</version>
|
<version>2.10</version>
|
||||||
</dependency>
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
<dependency>
|
<groupId>xml-apis</groupId>
|
||||||
<groupId>org.apache.pdfbox</groupId>
|
<artifactId>xml-apis</artifactId>
|
||||||
<artifactId>preflight</artifactId>
|
</exclusion>
|
||||||
<version>2.0.27</version>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<!-- JAXB -->
|
||||||
<groupId>org.apache.pdfbox</groupId>
|
<dependency>
|
||||||
<artifactId>pdfbox</artifactId>
|
<groupId>jakarta.xml.bind</groupId>
|
||||||
<version>2.0.27</version>
|
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||||
</dependency>
|
<version>4.0.2</version>
|
||||||
<dependency>
|
</dependency>
|
||||||
<groupId>org.dom4j</groupId>
|
|
||||||
<artifactId>dom4j</artifactId>
|
|
||||||
<version>2.1.3</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
|
||||||
<version>5.9.1</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.vintage</groupId>
|
|
||||||
<artifactId>junit-vintage-engine</artifactId>
|
|
||||||
<version>5.9.1</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- CII to UBL conversion -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.helger</groupId>
|
|
||||||
<artifactId>en16931-cii2ubl</artifactId>
|
|
||||||
<version>1.4.10</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
|
<!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.glassfish.jaxb</groupId>
|
<groupId>org.glassfish.jaxb</groupId>
|
||||||
<artifactId>jaxb-runtime</artifactId>
|
<artifactId>jaxb-runtime</artifactId>
|
||||||
<version>2.3.3</version>
|
<version>4.0.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.angus</groupId>
|
||||||
|
<artifactId>angus-activation</artifactId>
|
||||||
|
<version>2.0.2</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Apache PDFBox -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>preflight</artifactId>
|
||||||
|
<version>3.0.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>pdfbox</artifactId>
|
||||||
|
<version>3.0.2</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- DOM4j -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dom4j</groupId>
|
||||||
|
<artifactId>dom4j</artifactId>
|
||||||
|
<version>2.1.4</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- CII to UBL conversion -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.helger</groupId>
|
||||||
|
<artifactId>en16931-cii2ubl</artifactId>
|
||||||
|
<version>2.2.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<!-- test dependencies -->
|
||||||
<groupId>org.xmlunit</groupId>
|
<dependency>
|
||||||
<artifactId>xmlunit-core</artifactId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<version>2.10.0</version>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
<scope>test</scope>
|
<version>5.10.2</version>
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.xmlunit</groupId>
|
|
||||||
<artifactId>xmlunit-assertj</artifactId>
|
|
||||||
<version>2.9.1</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- API -->
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.junit.vintage</groupId>
|
||||||
<groupId>jakarta.xml.bind</groupId>
|
<artifactId>junit-vintage-engine</artifactId>
|
||||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
<version>5.10.2</version>
|
||||||
<version>2.3.3</version>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
</dependencies>
|
<groupId>org.xmlunit</groupId>
|
||||||
<build>
|
<artifactId>xmlunit-core</artifactId>
|
||||||
<plugins>
|
<version>2.10.0</version>
|
||||||
<plugin>
|
<scope>test</scope>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
</dependency>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<dependency>
|
||||||
<configuration>
|
<groupId>org.xmlunit</groupId>
|
||||||
<runOrder>alphabetical</runOrder>
|
<artifactId>xmlunit-assertj</artifactId>
|
||||||
</configuration>
|
<version>2.10.0</version>
|
||||||
</plugin>
|
<scope>test</scope>
|
||||||
<plugin>
|
</dependency>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<dependency>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<groupId>org.slf4j</groupId>
|
||||||
<version>3.6.1</version>
|
<artifactId>slf4j-simple</artifactId>
|
||||||
<configuration>
|
<version>2.0.9</version>
|
||||||
<descriptorRefs>
|
<scope>test</scope>
|
||||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
</dependency>
|
||||||
</descriptorRefs>
|
</dependencies>
|
||||||
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<runOrder>alphabetical</runOrder>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
|
<configuration>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
|
||||||
mvn clean compile assembly:single -->
|
mvn clean compile assembly:single -->
|
||||||
<!-- or whatever version you use -->
|
<!-- or whatever version you use -->
|
||||||
<source>8</source>
|
<source>11</source>
|
||||||
<target>8</target>
|
<target>11</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>3.2.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>**/logback.xml</exclude>
|
<exclude>**/logback.xml</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
<archive>
|
<archive>
|
||||||
<manifest>
|
<manifest>
|
||||||
<addClasspath>true</addClasspath>
|
<addClasspath>true</addClasspath>
|
||||||
</manifest>
|
</manifest>
|
||||||
<manifestSections>
|
<manifestSections>
|
||||||
<manifestSection>
|
<manifestSection>
|
||||||
<name>FreeSans.ttf</name>
|
<name>FreeSans.ttf</name>
|
||||||
<manifestEntries>
|
<manifestEntries>
|
||||||
<Content-Type>font/ttf</Content-Type>
|
<Content-Type>font/ttf</Content-Type>
|
||||||
</manifestEntries>
|
</manifestEntries>
|
||||||
</manifestSection>
|
</manifestSection>
|
||||||
<manifestSection>
|
<manifestSection>
|
||||||
<name>FreeSerif.ttf</name>
|
<name>FreeSerif.ttf</name>
|
||||||
<manifestEntries>
|
<manifestEntries>
|
||||||
<Content-Type>application/x-font</Content-Type>
|
<Content-Type>application/x-font</Content-Type>
|
||||||
</manifestEntries>
|
</manifestEntries>
|
||||||
</manifestSection>
|
</manifestSection>
|
||||||
<manifestSection>
|
<manifestSection>
|
||||||
<name>Times-Bold.ttf</name>
|
<name>Times-Bold.ttf</name>
|
||||||
<manifestEntries>
|
<manifestEntries>
|
||||||
<Content-Type>application/x-font</Content-Type>
|
<Content-Type>application/x-font</Content-Type>
|
||||||
</manifestEntries>
|
</manifestEntries>
|
||||||
</manifestSection>
|
</manifestSection>
|
||||||
</manifestSections>
|
</manifestSections>
|
||||||
</archive>
|
</archive>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
<version>3.2.1</version>
|
<version>3.3.1</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>attach-sources</id>
|
<id>attach-sources</id>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>jar-no-fork</goal>
|
<goal>jar-no-fork</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>3.2.1</version>
|
<version>3.5.3</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<shadedArtifactAttached>true</shadedArtifactAttached>
|
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||||
<minimizeJar>false</minimizeJar><!-- no longer java 11 compatible if set to true because it removes e.g. javax/xml/bind/annotation/XmlSchema-->
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
<filters>
|
<filters>
|
||||||
|
<filter>
|
||||||
<filter>
|
<artifact>*:*</artifact>
|
||||||
<artifact>*:*</artifact>
|
<excludes>
|
||||||
<excludes>
|
<exclude>META-INF/*.SF</exclude>
|
||||||
<exclude>META-INF/*.SF</exclude>
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
<exclude>META-INF/*.DSA</exclude>
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
<exclude>META-INF/*.RSA</exclude>
|
</excludes>
|
||||||
</excludes>
|
</filter>
|
||||||
</filter>
|
</filters>
|
||||||
<filter>
|
</configuration>
|
||||||
<artifact>log4j:log4j</artifact>
|
<executions>
|
||||||
<includes>
|
<execution>
|
||||||
<include>**</include>
|
<phase>package</phase>
|
||||||
</includes>
|
<goals>
|
||||||
</filter>
|
<goal>shade</goal>
|
||||||
<filter>
|
</goals>
|
||||||
<artifact>commons-logging:commons-logging</artifact>
|
</execution>
|
||||||
<includes>
|
</executions>
|
||||||
<include>**</include>
|
</plugin>
|
||||||
</includes>
|
<plugin>
|
||||||
</filter>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
</filters>
|
<artifactId>templating-maven-plugin</artifactId>
|
||||||
</configuration>
|
<version>1.0.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<id>filtering-java-templates</id>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>shade</goal>
|
<goal>filter-sources</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
</execution>
|
||||||
<artifactSet>
|
</executions>
|
||||||
<excludes>
|
</plugin>
|
||||||
<!--exclude>classworlds:classworlds</exclude> <exclude>junit:junit</exclude>
|
</plugins>
|
||||||
<exclude>jmock:*</exclude> <exclude>*:xml-apis</exclude> <exclude>org.apache.maven:lib:tests</exclude>
|
</build>
|
||||||
<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>
|
|
||||||
|
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
<profile> <!-- enforce building binaries with Java 1.8 for Maven Central, otherwise using them e.g. as jar will throw a version exception-->
|
<profile> <!-- enforce building binaries with Java 1.8 for Maven Central, otherwise using them e.g. as jar will throw a version exception-->
|
||||||
<id>release-sign-artifacts</id>
|
<id>release-sign-artifacts</id>
|
||||||
<activation>
|
<activation>
|
||||||
<property>
|
<property>
|
||||||
<name>performRelease</name>
|
<name>performRelease</name>
|
||||||
<value>true</value>
|
<value>true</value>
|
||||||
</property>
|
</property>
|
||||||
</activation>
|
</activation>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-toolchains-plugin</artifactId>
|
<artifactId>maven-toolchains-plugin</artifactId>
|
||||||
<version>3.1.0</version>
|
<version>3.1.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>toolchain</goal>
|
<goal>toolchain</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
<configuration>
|
||||||
<toolchains>
|
<toolchains>
|
||||||
<jdk>
|
<jdk>
|
||||||
<version>8</version>
|
<version>11</version>
|
||||||
<vendor>adopt</vendor>
|
<vendor>adopt</vendor>
|
||||||
</jdk>
|
</jdk>
|
||||||
</toolchains>
|
</toolchains>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
<mailingLists>
|
<mailingLists>
|
||||||
<mailingList>
|
<mailingList>
|
||||||
<name>User List</name>
|
<name>User List</name>
|
||||||
<archive>https://groups.google.com/forum/?hl=de#!forum/mustangproject</archive>
|
<archive>https://groups.google.com/forum/?hl=de#!forum/mustangproject</archive>
|
||||||
</mailingList>
|
</mailingList>
|
||||||
</mailingLists>
|
</mailingLists>
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
<name>Apache License, Version 2.0</name>
|
<name>Apache License, Version 2.0</name>
|
||||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||||
<distribution>repo</distribution>
|
<distribution>repo</distribution>
|
||||||
<comments>A business-friendly OSS license</comments>
|
<comments>A business-friendly OSS license</comments>
|
||||||
</license>
|
</license>
|
||||||
</licenses>
|
</licenses>
|
||||||
<developers>
|
<developers>
|
||||||
<developer>
|
<developer>
|
||||||
<name>Jochen Stärk</name>
|
<name>Jochen Stärk</name>
|
||||||
<email>jstaerk@usegroup.de</email>
|
<email>jstaerk@usegroup.de</email>
|
||||||
<roles>
|
<roles>
|
||||||
<role>architect</role>
|
<role>architect</role>
|
||||||
<role>developer</role>
|
<role>developer</role>
|
||||||
</roles>
|
</roles>
|
||||||
</developer>
|
</developer>
|
||||||
<developer>
|
<developer>
|
||||||
<name>Alexander Schmidt</name>
|
<name>Alexander Schmidt</name>
|
||||||
<email>schmidt.alexander@mail.de</email>
|
<email>schmidt.alexander@mail.de</email>
|
||||||
<roles>
|
<roles>
|
||||||
<role>developer</role>
|
<role>developer</role>
|
||||||
</roles>
|
</roles>
|
||||||
</developer>
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package org.mustangproject;
|
package org.mustangproject;
|
||||||
|
|
||||||
import org.mustangproject.ZUGFeRD.IExportableTransaction;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* (absolute) allowances on item and document level
|
* (absolute) allowances on item and document level
|
||||||
*/
|
*/
|
||||||
public class Allowance extends Charge implements IZUGFeRDAllowanceCharge {
|
public class Allowance extends Charge {
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* bean constructor
|
* bean constructor
|
||||||
@@ -31,6 +30,7 @@ public class Allowance extends Charge implements IZUGFeRDAllowanceCharge {
|
|||||||
* @return false since its not supposed to be calculated negatively
|
* @return false since its not supposed to be calculated negatively
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
public boolean isCharge() {
|
public boolean isCharge() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.mustangproject;
|
package org.mustangproject;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlementPayment;
|
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlementPayment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,6 +20,10 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
|
|||||||
* the "name" of the bank account (holder)
|
* the "name" of the bank account (holder)
|
||||||
*/
|
*/
|
||||||
protected String accountName=null;
|
protected String accountName=null;
|
||||||
|
/***
|
||||||
|
* bean constructor
|
||||||
|
*/
|
||||||
|
public BankDetails() { }
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* constructor for IBAN only :-)
|
* constructor for IBAN only :-)
|
||||||
@@ -80,12 +86,14 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
|
|||||||
* */
|
* */
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@JsonIgnore
|
||||||
public String getOwnBIC() {
|
public String getOwnBIC() {
|
||||||
return getBIC();
|
return getBIC();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@JsonIgnore
|
||||||
public String getOwnIBAN() {
|
public String getOwnIBAN() {
|
||||||
return getIBAN();
|
return getIBAN();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ import java.io.Serializable;
|
|||||||
|
|
||||||
import com.helger.commons.error.list.ErrorList;
|
import com.helger.commons.error.list.ErrorList;
|
||||||
import com.helger.en16931.cii2ubl.CIIToUBL23Converter;
|
import com.helger.en16931.cii2ubl.CIIToUBL23Converter;
|
||||||
import com.helger.ubl21.UBL21Writer;
|
import com.helger.ubl23.UBL23Marshaller;
|
||||||
import com.helger.ubl22.UBL22Writer;
|
|
||||||
import com.helger.ubl23.UBL23Writer;
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* converts a Cross Industry Invoice XML file to a UBL XML file
|
* converts a Cross Industry Invoice XML file to a UBL XML file
|
||||||
@@ -23,39 +21,15 @@ public class CIIToUBL {
|
|||||||
final ErrorList occurred=new ErrorList();
|
final ErrorList occurred=new ErrorList();
|
||||||
final CIIToUBL23Converter cc=new CIIToUBL23Converter();
|
final CIIToUBL23Converter cc=new CIIToUBL23Converter();
|
||||||
final Serializable aUBL = cc.convertCIItoUBL(input, occurred);
|
final Serializable aUBL = cc.convertCIItoUBL(input, occurred);
|
||||||
if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.invoice_21.InvoiceType)
|
if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.invoice_23.InvoiceType)
|
||||||
{
|
{
|
||||||
UBL21Writer.invoice ()
|
UBL23Marshaller.invoice ()
|
||||||
.setFormattedOutput (true)
|
|
||||||
.write ((oasis.names.specification.ubl.schema.xsd.invoice_21.InvoiceType) aUBL, output);
|
|
||||||
}
|
|
||||||
else if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.creditnote_21.CreditNoteType)
|
|
||||||
{
|
|
||||||
UBL21Writer.creditNote ()
|
|
||||||
.setFormattedOutput (true)
|
|
||||||
.write ((oasis.names.specification.ubl.schema.xsd.creditnote_21.CreditNoteType) aUBL, output);
|
|
||||||
}
|
|
||||||
else if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.invoice_22.InvoiceType)
|
|
||||||
{
|
|
||||||
UBL22Writer.invoice ()
|
|
||||||
.setFormattedOutput (true)
|
|
||||||
.write ((oasis.names.specification.ubl.schema.xsd.invoice_22.InvoiceType) aUBL, output);
|
|
||||||
}
|
|
||||||
else if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.creditnote_22.CreditNoteType)
|
|
||||||
{
|
|
||||||
UBL22Writer.creditNote ()
|
|
||||||
.setFormattedOutput (true)
|
|
||||||
.write ((oasis.names.specification.ubl.schema.xsd.creditnote_22.CreditNoteType) aUBL, output);
|
|
||||||
}
|
|
||||||
else if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.invoice_23.InvoiceType)
|
|
||||||
{
|
|
||||||
UBL23Writer.invoice ()
|
|
||||||
.setFormattedOutput (true)
|
.setFormattedOutput (true)
|
||||||
.write ((oasis.names.specification.ubl.schema.xsd.invoice_23.InvoiceType) aUBL, output);
|
.write ((oasis.names.specification.ubl.schema.xsd.invoice_23.InvoiceType) aUBL, output);
|
||||||
}
|
}
|
||||||
else if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.creditnote_23.CreditNoteType)
|
else if (aUBL instanceof oasis.names.specification.ubl.schema.xsd.creditnote_23.CreditNoteType)
|
||||||
{
|
{
|
||||||
UBL23Writer.creditNote ()
|
UBL23Marshaller.creditNote ()
|
||||||
.setFormattedOutput (true)
|
.setFormattedOutput (true)
|
||||||
.write ((oasis.names.specification.ubl.schema.xsd.creditnote_23.CreditNoteType) aUBL, output);
|
.write ((oasis.names.specification.ubl.schema.xsd.creditnote_23.CreditNoteType) aUBL, output);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2023 Jochen Stärk, see LICENSE file
|
||||||
|
package org.mustangproject;
|
||||||
|
|
||||||
|
|
||||||
|
import org.mustangproject.ZUGFeRD.TransactionCalculator;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class CalculatedInvoice extends Invoice implements Serializable {
|
||||||
|
|
||||||
|
protected BigDecimal grandTotal=null;
|
||||||
|
|
||||||
|
public void calculate() {
|
||||||
|
TransactionCalculator tc=new TransactionCalculator(this);
|
||||||
|
grandTotal=tc.getGrandTotal();
|
||||||
|
}
|
||||||
|
public BigDecimal getGrandTotal() {
|
||||||
|
if (grandTotal==null) {
|
||||||
|
calculate();
|
||||||
|
}
|
||||||
|
return grandTotal;
|
||||||
|
}
|
||||||
|
public CalculatedInvoice setGrandTotal(BigDecimal grand) {
|
||||||
|
grandTotal=grand;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
59
library/src/main/java/org/mustangproject/CashDiscount.java
Normal file
59
library/src/main/java/org/mustangproject/CashDiscount.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package org.mustangproject;
|
||||||
|
|
||||||
|
import org.mustangproject.ZUGFeRD.IZUGFeRDCashDiscount;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* A class to represent discounts for early payments ("Skonto")
|
||||||
|
*/
|
||||||
|
public class CashDiscount implements IZUGFeRDCashDiscount {
|
||||||
|
|
||||||
|
/***
|
||||||
|
* the reduction percent allowed in the period
|
||||||
|
*/
|
||||||
|
protected BigDecimal percent;
|
||||||
|
/***
|
||||||
|
* the period (usually days) count how long the percent apply
|
||||||
|
*/
|
||||||
|
protected Integer days=null;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Create a cash discount (skonto) with the specified height in the specified period.
|
||||||
|
* Should someone add more period types than just "days" there
|
||||||
|
* is be space for a (optional) third parameter
|
||||||
|
*
|
||||||
|
* @param percent max 3 decimals "behind the dot", more precision is currently ignored
|
||||||
|
* @param days the count of the periods (usually days) the percentage applies
|
||||||
|
*/
|
||||||
|
public CashDiscount(BigDecimal percent, int days) {
|
||||||
|
this.percent = percent;
|
||||||
|
this.days = days;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @return this particular cash discount as cross industry invoice XML
|
||||||
|
*/
|
||||||
|
public String getAsCII() {
|
||||||
|
return "<ram:SpecifiedTradePaymentTerms>"+
|
||||||
|
"<ram:Description>Cash Discount</ram:Description>"+
|
||||||
|
" <ram:ApplicableTradePaymentDiscountTerms>"+
|
||||||
|
" <ram:BasisPeriodMeasure unitCode=\"DAY\">"+days+"</ram:BasisPeriodMeasure>"+
|
||||||
|
" <ram:CalculationPercent>"+XMLTools.nDigitFormat(percent,3)+"</ram:CalculationPercent>"+
|
||||||
|
" </ram:ApplicableTradePaymentDiscountTerms>"+
|
||||||
|
"</ram:SpecifiedTradePaymentTerms>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* since EN16931 voted not to have (or even allow) cash discounts in their core invoice the german
|
||||||
|
* XRechnung CIUS defined it's own proprietary format for a freetext field
|
||||||
|
* @return this particular cash discount in proprietary xrechnung format
|
||||||
|
*/
|
||||||
|
public String getAsXRechnung() {
|
||||||
|
return "#SKONTO#TAGE="+days+"#PROZENT="+XMLTools.nDigitFormat(percent,2)+"#\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
package org.mustangproject;
|
package org.mustangproject;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import org.mustangproject.ZUGFeRD.IAbsoluteValueProvider;
|
import org.mustangproject.ZUGFeRD.IAbsoluteValueProvider;
|
||||||
import org.mustangproject.ZUGFeRD.IExportableTransaction;
|
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
|
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
@@ -28,6 +27,10 @@ public class Charge implements IZUGFeRDAllowanceCharge {
|
|||||||
* a simple human readable description
|
* a simple human readable description
|
||||||
*/
|
*/
|
||||||
protected String reason;
|
protected String reason;
|
||||||
|
/**
|
||||||
|
* Code from list UNTDID 5189
|
||||||
|
*/
|
||||||
|
protected String reasonCode;
|
||||||
/**
|
/**
|
||||||
* the category ID why this charge has been applied
|
* the category ID why this charge has been applied
|
||||||
*/
|
*/
|
||||||
@@ -96,14 +99,38 @@ public class Charge implements IZUGFeRDAllowanceCharge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getReasonCode() {
|
||||||
|
return reasonCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Reason code for the charge
|
||||||
|
* @param reasonCode from list UNTDID 5189
|
||||||
|
* @return fluid setter
|
||||||
|
*/
|
||||||
|
public Charge setReasonCode(String reasonCode) {
|
||||||
|
this.reasonCode = reasonCode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) {
|
public BigDecimal getTotalAmount(IAbsoluteValueProvider currentItem) {
|
||||||
|
if (percent!=null) {
|
||||||
|
return currentItem.getValue().multiply(getPercent().divide(new BigDecimal(100)));
|
||||||
|
} else if(totalAmount != null) {
|
||||||
|
return totalAmount;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("percent must be set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getTotalAmount() {
|
||||||
if (totalAmount!=null) {
|
if (totalAmount!=null) {
|
||||||
return totalAmount;
|
return totalAmount;
|
||||||
} else if (percent!=null) {
|
|
||||||
return currentItem.getValue().multiply(getPercent().divide(new BigDecimal(100)));
|
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Either totalAmount or percent must be set");
|
throw new RuntimeException("totalAmount must be set");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,6 +152,7 @@ public class Charge implements IZUGFeRDAllowanceCharge {
|
|||||||
* @return true since it is supposed to be calculated negatively
|
* @return true since it is supposed to be calculated negatively
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
public boolean isCharge() {
|
public boolean isCharge() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -139,7 +167,7 @@ public class Charge implements IZUGFeRDAllowanceCharge {
|
|||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* machine readable reason for this allowance/charge
|
* the category ID why this has been applied
|
||||||
* @param categoryCode usually S
|
* @param categoryCode usually S
|
||||||
* @return fluid setter
|
* @return fluid setter
|
||||||
*/
|
*/
|
||||||
|
|||||||
104
library/src/main/java/org/mustangproject/ClassCode.java
Normal file
104
library/src/main/java/org/mustangproject/ClassCode.java
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
* *********************************************************************
|
||||||
|
* <p>
|
||||||
|
* Copyright (c) 2024 Jan N. Klug
|
||||||
|
* <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;
|
||||||
|
|
||||||
|
import org.w3c.dom.NamedNodeMap;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A schemed classification for products. The scheme can be anything defined in UNTDID 7143.
|
||||||
|
*/
|
||||||
|
public class ClassCode {
|
||||||
|
private final String listID;
|
||||||
|
private final String code;
|
||||||
|
private String listVersionID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A UNTDID 7143 schemed classification code
|
||||||
|
*
|
||||||
|
* @param listID the scheme from UNTDID 7143
|
||||||
|
* @param code the classification code
|
||||||
|
* @param listVersionID an (optional) version of the scheme
|
||||||
|
*/
|
||||||
|
public ClassCode(String listID, String code, String listVersionID) {
|
||||||
|
this.listID = listID;
|
||||||
|
this.code = code;
|
||||||
|
this.listVersionID = listVersionID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A UNTDID 7143 schemed classification code
|
||||||
|
*
|
||||||
|
* @param listID the scheme from UNTDID 7143
|
||||||
|
* @param code the classification code
|
||||||
|
*/
|
||||||
|
public ClassCode(String listID, String code) {
|
||||||
|
this(listID, code, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Set the version for the scheme returned by {@link #getListID()}
|
||||||
|
* @param listVersionID the scheme version
|
||||||
|
*/
|
||||||
|
public void setListVersionID(String listVersionID) {
|
||||||
|
this.listVersionID = listVersionID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the scheme (according to UNTDID 7143) that describes the value returned by {@link #getCode()},
|
||||||
|
* potentially versioned by {@link #getListVersionID()}
|
||||||
|
*
|
||||||
|
* @return the scheme
|
||||||
|
*/
|
||||||
|
public String getListID() {
|
||||||
|
return listID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the code that (following the scheme returned by {@link #getListID()}) describes the product
|
||||||
|
*
|
||||||
|
* @return the classification code itself
|
||||||
|
*/
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the (optional) version for the scheme returned by {@link #getListID()}
|
||||||
|
*
|
||||||
|
* @return the version or {@code null} if not set
|
||||||
|
*/
|
||||||
|
public String getListVersionID() {
|
||||||
|
return listVersionID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassCode fromNode(Node node) {
|
||||||
|
NamedNodeMap attrs = node.getAttributes();
|
||||||
|
if (attrs != null && attrs.getNamedItem("listID") != null) {
|
||||||
|
ClassCode classCode = new ClassCode(attrs.getNamedItem("listID").getNodeValue(), node.getTextContent());
|
||||||
|
if (attrs.getNamedItem("listVersionID") != null) {
|
||||||
|
classCode.setListVersionID(attrs.getNamedItem("listVersionID").getNodeValue());
|
||||||
|
}
|
||||||
|
return classCode;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* *********************************************************************
|
||||||
|
* <p>
|
||||||
|
* Copyright (c) 2024 Jan N. Klug
|
||||||
|
* <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;
|
||||||
|
|
||||||
|
import org.mustangproject.ZUGFeRD.IDesignatedProductClassification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of {@link IDesignatedProductClassification} for describing a {@link org.mustangproject.Product}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DesignatedProductClassification implements IDesignatedProductClassification {
|
||||||
|
private final ClassCode classCode;
|
||||||
|
private String className;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A schemed product descriptor
|
||||||
|
*
|
||||||
|
* @param classCode an UNTDID 7143 schemed class code
|
||||||
|
* @param className a verbal description of the class code
|
||||||
|
*/
|
||||||
|
public DesignatedProductClassification(ClassCode classCode, String className) {
|
||||||
|
this.classCode = classCode;
|
||||||
|
this.className = className;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A schemed product descriptor
|
||||||
|
*
|
||||||
|
* @param classCode an UNTDID 7143 schemed class code
|
||||||
|
*/
|
||||||
|
public DesignatedProductClassification(ClassCode classCode) {
|
||||||
|
this(classCode, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassCode getClassCode() {
|
||||||
|
return classCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getClassName() {
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the human-readable name of the class code
|
||||||
|
*
|
||||||
|
* @param className the name of the class code (can be {@code null})
|
||||||
|
*/
|
||||||
|
public void setClassName(String className) {
|
||||||
|
this.className = className;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
library/src/main/java/org/mustangproject/DirectDebit.java
Normal file
42
library/src/main/java/org/mustangproject/DirectDebit.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package org.mustangproject;
|
||||||
|
|
||||||
|
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlementDebit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provides e.g. the IBAN to transfer money to :-)
|
||||||
|
*/
|
||||||
|
public class DirectDebit implements IZUGFeRDTradeSettlementDebit {
|
||||||
|
/**
|
||||||
|
* Debited account identifier (BT-91)
|
||||||
|
*/
|
||||||
|
protected final String IBAN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mandate reference identifier (BT-89)
|
||||||
|
*/
|
||||||
|
protected final String mandate;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* constructor for normal use :-)
|
||||||
|
* @param IBAN the IBAN as string
|
||||||
|
* @param mandate the mandate as string
|
||||||
|
*/
|
||||||
|
public DirectDebit(String IBAN, String mandate) {
|
||||||
|
this.IBAN = IBAN;
|
||||||
|
this.mandate = mandate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* getter for the IBAN
|
||||||
|
* @return IBAN
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getIBAN() {
|
||||||
|
return this.IBAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMandate() {
|
||||||
|
return this.mandate;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.mustangproject;
|
package org.mustangproject;
|
||||||
|
|
||||||
public enum EStandard {
|
public enum EStandard {
|
||||||
facturx, orderx, despatchadvice, ubldespatchadvice, zugferd, cii, ubl
|
facturx, orderx, despatchadvice, ubldespatchadvice, zugferd, cii, ubl, ubl_creditnote
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,8 @@ import java.util.Collection;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.mustangproject.ZUGFeRD.IExportableTransaction;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
|
import org.mustangproject.ZUGFeRD.*;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
|
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTradeParty;
|
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDPaymentTerms;
|
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlement;
|
|
||||||
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
|
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
@@ -42,34 +38,38 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
|||||||
* @see IExportableTransaction if you want to implement an interface instead
|
* @see IExportableTransaction if you want to implement an interface instead
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
public class Invoice implements IExportableTransaction {
|
public class Invoice implements IExportableTransaction {
|
||||||
|
|
||||||
protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, invoiceReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null;
|
protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, invoiceReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null;
|
||||||
protected Date issueDate = null, dueDate = null, deliveryDate = null;
|
protected Date issueDate = null, dueDate = null, deliveryDate = null;
|
||||||
protected TradeParty sender = null, recipient = null, deliveryAddress = null;
|
protected TradeParty sender = null, recipient = null, deliveryAddress = null, payee = null;
|
||||||
@JsonDeserialize(contentAs=Item.class)
|
protected ArrayList<CashDiscount> cashDiscounts = null;
|
||||||
|
@JsonDeserialize(contentAs = Item.class)
|
||||||
protected ArrayList<IZUGFeRDExportableItem> ZFItems = null;
|
protected ArrayList<IZUGFeRDExportableItem> ZFItems = null;
|
||||||
protected ArrayList<String> notes = null;
|
protected ArrayList<String> notes = null;
|
||||||
private List<IncludedNote> includedNotes = null;
|
private List<IncludedNote> includedNotes = null;
|
||||||
protected String sellerOrderReferencedDocumentID;
|
protected String sellerOrderReferencedDocumentID;
|
||||||
protected String contractReferencedDocument = null;
|
protected String contractReferencedDocument = null;
|
||||||
protected ArrayList<FileAttachment> xmlEmbeddedFiles=null;
|
protected ArrayList<FileAttachment> xmlEmbeddedFiles = null;
|
||||||
|
|
||||||
protected BigDecimal totalPrepaidAmount = null;
|
protected BigDecimal totalPrepaidAmount = null;
|
||||||
protected Date detailedDeliveryDateStart = null;
|
protected Date detailedDeliveryDateStart = null;
|
||||||
protected Date detailedDeliveryPeriodEnd = null;
|
protected Date detailedDeliveryPeriodEnd = null;
|
||||||
|
|
||||||
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>(),
|
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>(),
|
||||||
Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>();
|
Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>();
|
||||||
protected IZUGFeRDPaymentTerms paymentTerms = null;
|
protected IZUGFeRDPaymentTerms paymentTerms = null;
|
||||||
protected Date invoiceReferencedIssueDate;
|
protected Date invoiceReferencedIssueDate;
|
||||||
protected String specifiedProcuringProjectID = null;
|
protected String specifiedProcuringProjectID = null;
|
||||||
protected String specifiedProcuringProjectName = null;
|
protected String specifiedProcuringProjectName = null;
|
||||||
protected String despatchAdviceReferencedDocumentID = null;
|
protected String despatchAdviceReferencedDocumentID = null;
|
||||||
protected String vatDueDateTypeCode = null;
|
protected String vatDueDateTypeCode = null;
|
||||||
|
protected String creditorReferenceID; // required when direct debit is used.
|
||||||
|
|
||||||
public Invoice() {
|
public Invoice() {
|
||||||
ZFItems = new ArrayList<>();
|
ZFItems = new ArrayList<>();
|
||||||
|
cashDiscounts = new ArrayList<>();
|
||||||
setCurrency("EUR");
|
setCurrency("EUR");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ public class Invoice implements IExportableTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getContractReferencedDocument() {
|
public String getContractReferencedDocument() {
|
||||||
return contractReferencedDocument;
|
return contractReferencedDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,14 +100,14 @@ public class Invoice implements IExportableTransaction {
|
|||||||
|
|
||||||
public Invoice embedFileInXML(FileAttachment fa) {
|
public Invoice embedFileInXML(FileAttachment fa) {
|
||||||
if (xmlEmbeddedFiles == null) {
|
if (xmlEmbeddedFiles == null) {
|
||||||
xmlEmbeddedFiles= new ArrayList<>();
|
xmlEmbeddedFiles = new ArrayList<>();
|
||||||
}
|
}
|
||||||
xmlEmbeddedFiles.add(fa);
|
xmlEmbeddedFiles.add(fa);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileAttachment[] getAdditionalReferencedDocuments() {
|
public FileAttachment[] getAdditionalReferencedDocuments() {
|
||||||
if (xmlEmbeddedFiles == null) {
|
if (xmlEmbeddedFiles == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -115,6 +115,10 @@ public class Invoice implements IExportableTransaction {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IZUGFeRDCashDiscount[] getCashDiscounts() {
|
||||||
|
return cashDiscounts.toArray(new IZUGFeRDCashDiscount[0]);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getNumber() {
|
public String getNumber() {
|
||||||
@@ -139,6 +143,7 @@ public class Invoice implements IExportableTransaction {
|
|||||||
documentCode = DocumentCodeTypeConstants.CORRECTEDINVOICE;
|
documentCode = DocumentCodeTypeConstants.CORRECTEDINVOICE;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Invoice setCreditNote() {
|
public Invoice setCreditNote() {
|
||||||
documentCode = DocumentCodeTypeConstants.CREDITNOTE;
|
documentCode = DocumentCodeTypeConstants.CREDITNOTE;
|
||||||
return this;
|
return this;
|
||||||
@@ -229,16 +234,18 @@ public class Invoice implements IExportableTransaction {
|
|||||||
public String getBuyerOrderReferencedDocumentID() {
|
public String getBuyerOrderReferencedDocumentID() {
|
||||||
return buyerOrderReferencedDocumentID;
|
return buyerOrderReferencedDocumentID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSellerOrderReferencedDocumentID() {
|
public String getSellerOrderReferencedDocumentID() {
|
||||||
return sellerOrderReferencedDocumentID;
|
return sellerOrderReferencedDocumentID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Invoice setSellerOrderReferencedDocumentID(String sellerOrderReferencedDocumentID) {
|
public Invoice setSellerOrderReferencedDocumentID(String sellerOrderReferencedDocumentID) {
|
||||||
this.sellerOrderReferencedDocumentID = sellerOrderReferencedDocumentID;
|
this.sellerOrderReferencedDocumentID = sellerOrderReferencedDocumentID;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* usually the order number
|
* usually the order number
|
||||||
* @param buyerOrderReferencedDocumentID string with number
|
* @param buyerOrderReferencedDocumentID string with number
|
||||||
@@ -258,22 +265,23 @@ public class Invoice implements IExportableTransaction {
|
|||||||
this.invoiceReferencedDocumentID = invoiceReferencedDocumentID;
|
this.invoiceReferencedDocumentID = invoiceReferencedDocumentID;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getInvoiceReferencedDocumentID() {
|
public String getInvoiceReferencedDocumentID() {
|
||||||
return invoiceReferencedDocumentID;
|
return invoiceReferencedDocumentID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date getInvoiceReferencedIssueDate() {
|
public Date getInvoiceReferencedIssueDate() {
|
||||||
return invoiceReferencedIssueDate;
|
return invoiceReferencedIssueDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Invoice setInvoiceReferencedIssueDate(Date issueDate) {
|
public Invoice setInvoiceReferencedIssueDate(Date issueDate) {
|
||||||
this.invoiceReferencedIssueDate = issueDate;
|
this.invoiceReferencedIssueDate = issueDate;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getBuyerOrderReferencedDocumentIssueDateTime() {
|
public String getBuyerOrderReferencedDocumentIssueDateTime() {
|
||||||
return buyerOrderReferencedDocumentIssueDateTime;
|
return buyerOrderReferencedDocumentIssueDateTime;
|
||||||
}
|
}
|
||||||
@@ -285,7 +293,7 @@ public class Invoice implements IExportableTransaction {
|
|||||||
* @return fluent setter
|
* @return fluent setter
|
||||||
*/
|
*/
|
||||||
public Invoice setTotalPrepaidAmount(BigDecimal prepaid) {
|
public Invoice setTotalPrepaidAmount(BigDecimal prepaid) {
|
||||||
totalPrepaidAmount=prepaid;
|
totalPrepaidAmount = prepaid;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,13 +388,13 @@ public class Invoice implements IExportableTransaction {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getOwnLocation() {
|
public String getOwnLocation() {
|
||||||
return sender.getLocation();
|
return sender.getLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getOwnCountry() {
|
public String getOwnCountry() {
|
||||||
return sender.getCountry();
|
return sender.getCountry();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,12 +407,12 @@ public class Invoice implements IExportableTransaction {
|
|||||||
return notes.toArray(new String[0]);
|
return notes.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<IncludedNote> getNotesWithSubjectCode() {
|
public List<IncludedNote> getNotesWithSubjectCode() {
|
||||||
return includedNotes;
|
return includedNotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCurrency() {
|
public String getCurrency() {
|
||||||
return currency;
|
return currency;
|
||||||
}
|
}
|
||||||
@@ -473,13 +481,14 @@ public class Invoice implements IExportableTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TradeParty getRecipient() {
|
public TradeParty getRecipient() {
|
||||||
return recipient;
|
return recipient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* required.
|
* required.
|
||||||
* sets the invoice receiving institution = invoicee
|
* sets the invoice receiving institution = invoicee
|
||||||
|
*
|
||||||
* @param recipient the invoicee organisation
|
* @param recipient the invoicee organisation
|
||||||
* @return fluent setter
|
* @return fluent setter
|
||||||
*/
|
*/
|
||||||
@@ -491,6 +500,7 @@ public class Invoice implements IExportableTransaction {
|
|||||||
/**
|
/**
|
||||||
* required.
|
* required.
|
||||||
* sets the invoicing institution = invoicer
|
* sets the invoicing institution = invoicer
|
||||||
|
*
|
||||||
* @param sender the invoicer
|
* @param sender the invoicer
|
||||||
* @return fluent setter
|
* @return fluent setter
|
||||||
*/
|
*/
|
||||||
@@ -508,8 +518,22 @@ public class Invoice implements IExportableTransaction {
|
|||||||
if (Allowances.isEmpty()) {
|
if (Allowances.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return Allowances.toArray(new IZUGFeRDAllowanceCharge[0]);
|
return Allowances.toArray(new IZUGFeRDAllowanceCharge[0]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* this is wrong and only used from jackson
|
||||||
|
* @param iza
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Invoice setZFAllowances(Allowance[] iza) {
|
||||||
|
Allowances=new ArrayList<>();
|
||||||
|
|
||||||
|
for (IZUGFeRDAllowanceCharge cz:iza) {
|
||||||
|
Allowances.add(cz);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -518,18 +542,30 @@ public class Invoice implements IExportableTransaction {
|
|||||||
if (Charges.isEmpty()) {
|
if (Charges.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return Charges.toArray(new IZUGFeRDAllowanceCharge[0]);
|
return Charges.toArray(new IZUGFeRDAllowanceCharge[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* this is wrong and only used from jackson
|
||||||
|
* @param iza
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Invoice setZFCharges(Charge[] iza) {
|
||||||
|
Charges=new ArrayList<>();
|
||||||
|
for (IZUGFeRDAllowanceCharge cz:iza) {
|
||||||
|
Charges.add(cz);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
|
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {
|
||||||
if (LogisticsServiceCharges.isEmpty()) {
|
if (LogisticsServiceCharges.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return LogisticsServiceCharges.toArray(new IZUGFeRDAllowanceCharge[0]);
|
return LogisticsServiceCharges.toArray(new IZUGFeRDAllowanceCharge[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -540,7 +576,7 @@ public class Invoice implements IExportableTransaction {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((TradeParty) getSender()).getAsTradeSettlement();
|
return getSender().getAsTradeSettlement();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,21 +606,48 @@ public class Invoice implements IExportableTransaction {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TradeParty getPayee() {
|
||||||
|
return this.payee;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* if the payee is not the seller, it can be specified here
|
||||||
|
* @param payee the payment receiving organisation
|
||||||
|
* @return fluent setter
|
||||||
|
*/
|
||||||
|
public Invoice setPayee(TradeParty payee) {
|
||||||
|
this.payee = payee;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Adds a cash discount (skonto)
|
||||||
|
* @param c the CashDiscount percent/period combination
|
||||||
|
* @return fluent setter
|
||||||
|
*/
|
||||||
|
public Invoice addCashDiscount(CashDiscount c) {
|
||||||
|
this.cashDiscounts.add(c);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IZUGFeRDExportableItem[] getZFItems() {
|
public IZUGFeRDExportableItem[] getZFItems() {
|
||||||
return ZFItems.toArray(new IZUGFeRDExportableItem[0]);
|
return ZFItems.toArray(new IZUGFeRDExportableItem[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setZFItems(ArrayList<IZUGFeRDExportableItem> ims) {
|
public void setZFItems(ArrayList<IZUGFeRDExportableItem> ims) {
|
||||||
ZFItems=ims;
|
ZFItems = ims;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* required
|
* required
|
||||||
* adds invoice "lines" :-)
|
* adds invoice "lines" :-)
|
||||||
* @see Item
|
*
|
||||||
* @param item the invoice line
|
* @param item the invoice line
|
||||||
* @return fluent setter
|
* @return fluent setter
|
||||||
|
* @see Item
|
||||||
*/
|
*/
|
||||||
public Invoice addItem(IZUGFeRDExportableItem item) {
|
public Invoice addItem(IZUGFeRDExportableItem item) {
|
||||||
ZFItems.add(item);
|
ZFItems.add(item);
|
||||||
@@ -669,6 +732,7 @@ public class Invoice implements IExportableTransaction {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* adds a free text paragraph, which will become an includedNote element
|
* adds a free text paragraph, which will become an includedNote element
|
||||||
|
*
|
||||||
* @param text freeform UTF8 plain text
|
* @param text freeform UTF8 plain text
|
||||||
* @return fluent setter
|
* @return fluent setter
|
||||||
*/
|
*/
|
||||||
@@ -679,129 +743,138 @@ public class Invoice implements IExportableTransaction {
|
|||||||
notes.add(text);
|
notes.add(text);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Invoice addNotes(Collection<IncludedNote> notes) {
|
|
||||||
if (notes == null) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
if (includedNotes == null) {
|
|
||||||
includedNotes = new ArrayList<>();
|
|
||||||
}
|
|
||||||
includedNotes.addAll(notes);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* adds a free text paragraph, which will become an includedNote element with explicit
|
|
||||||
* subjectCode {@link SubjectCode#AAI}
|
|
||||||
* @param content freeform UTF8 plain text
|
|
||||||
* @return fluent setter
|
|
||||||
*/
|
|
||||||
public Invoice addGeneralNote(String content) {
|
|
||||||
if (includedNotes == null) {
|
|
||||||
includedNotes = new ArrayList<>();
|
|
||||||
}
|
|
||||||
includedNotes.add(IncludedNote.generalNote(content));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public Invoice addNotes(Collection<IncludedNote> notes) {
|
||||||
* adds a free text paragraph, which will become an includedNote element with explicit
|
if (notes == null) {
|
||||||
* subjectCode {@link SubjectCode#REG}
|
return this;
|
||||||
* @param content freeform UTF8 plain text
|
}
|
||||||
* @return fluent setter
|
if (includedNotes == null) {
|
||||||
*/
|
includedNotes = new ArrayList<>();
|
||||||
public Invoice addRegulatoryNote(String content) {
|
}
|
||||||
if (includedNotes == null) {
|
includedNotes.addAll(notes);
|
||||||
includedNotes = new ArrayList<>();
|
return this;
|
||||||
}
|
}
|
||||||
includedNotes.add(IncludedNote.regulatoryNote(content));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* adds a free text paragraph, which will become an includedNote element with explicit
|
* adds a free text paragraph, which will become an includedNote element with explicit
|
||||||
* subjectCode {@link SubjectCode#ABL}
|
* subjectCode {@link SubjectCode#AAI}
|
||||||
* @param content freeform UTF8 plain text
|
*
|
||||||
* @return fluent setter
|
* @param content freeform UTF8 plain text
|
||||||
*/
|
* @return fluent setter
|
||||||
public Invoice addLegalNote(String content) {
|
*/
|
||||||
if (includedNotes == null) {
|
public Invoice addGeneralNote(String content) {
|
||||||
includedNotes = new ArrayList<>();
|
if (includedNotes == null) {
|
||||||
}
|
includedNotes = new ArrayList<>();
|
||||||
includedNotes.add(IncludedNote.legalNote(content));
|
}
|
||||||
return this;
|
includedNotes.add(IncludedNote.generalNote(content));
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* adds a free text paragraph, which will become an includedNote element with explicit
|
* adds a free text paragraph, which will become an includedNote element with explicit
|
||||||
* subjectCode {@link SubjectCode#CUS}
|
* subjectCode {@link SubjectCode#REG}
|
||||||
* @param content freeform UTF8 plain text
|
*
|
||||||
* @return fluent setter
|
* @param content freeform UTF8 plain text
|
||||||
*/
|
* @return fluent setter
|
||||||
public Invoice addCustomsNote(String content) {
|
*/
|
||||||
if (includedNotes == null) {
|
public Invoice addRegulatoryNote(String content) {
|
||||||
includedNotes = new ArrayList<>();
|
if (includedNotes == null) {
|
||||||
}
|
includedNotes = new ArrayList<>();
|
||||||
includedNotes.add(IncludedNote.customsNote(content));
|
}
|
||||||
return this;
|
includedNotes.add(IncludedNote.regulatoryNote(content));
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* adds a free text paragraph, which will become an includedNote element with explicit
|
* adds a free text paragraph, which will become an includedNote element with explicit
|
||||||
* subjectCode {@link SubjectCode#SUR}
|
* subjectCode {@link SubjectCode#ABL}
|
||||||
* @param content freeform UTF8 plain text
|
*
|
||||||
* @return fluent setter
|
* @param content freeform UTF8 plain text
|
||||||
*/
|
* @return fluent setter
|
||||||
public Invoice addSellerNote(String content) {
|
*/
|
||||||
if (includedNotes == null) {
|
public Invoice addLegalNote(String content) {
|
||||||
includedNotes = new ArrayList<>();
|
if (includedNotes == null) {
|
||||||
}
|
includedNotes = new ArrayList<>();
|
||||||
includedNotes.add(IncludedNote.sellerNote(content));
|
}
|
||||||
return this;
|
includedNotes.add(IncludedNote.legalNote(content));
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a free text paragraph, which will become an includedNote element with explicit
|
||||||
|
* subjectCode {@link SubjectCode#CUS}
|
||||||
|
*
|
||||||
|
* @param content freeform UTF8 plain text
|
||||||
|
* @return fluent setter
|
||||||
|
*/
|
||||||
|
public Invoice addCustomsNote(String content) {
|
||||||
|
if (includedNotes == null) {
|
||||||
|
includedNotes = new ArrayList<>();
|
||||||
|
}
|
||||||
|
includedNotes.add(IncludedNote.customsNote(content));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a free text paragraph, which will become an includedNote element with explicit
|
||||||
|
* subjectCode {@link SubjectCode#SUR}
|
||||||
|
*
|
||||||
|
* @param content freeform UTF8 plain text
|
||||||
|
* @return fluent setter
|
||||||
|
*/
|
||||||
|
public Invoice addSellerNote(String content) {
|
||||||
|
if (includedNotes == null) {
|
||||||
|
includedNotes = new ArrayList<>();
|
||||||
|
}
|
||||||
|
includedNotes.add(IncludedNote.sellerNote(content));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a free text paragraph, which will become an includedNote element with explicit
|
||||||
|
* subjectCode {@link SubjectCode#TXD}
|
||||||
|
*
|
||||||
|
* @param content freeform UTF8 plain text
|
||||||
|
* @return fluent setter
|
||||||
|
*/
|
||||||
|
public Invoice addTaxNote(String content) {
|
||||||
|
if (includedNotes == null) {
|
||||||
|
includedNotes = new ArrayList<>();
|
||||||
|
}
|
||||||
|
includedNotes.add(IncludedNote.taxNote(content));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a free text paragraph, which will become an includedNote element with explicit
|
||||||
|
* subjectCode {@link SubjectCode#ACY}
|
||||||
|
*
|
||||||
|
* @param content freeform UTF8 plain text
|
||||||
|
* @return fluent setter
|
||||||
|
*/
|
||||||
|
public Invoice addIntroductionNote(String content) {
|
||||||
|
if (includedNotes == null) {
|
||||||
|
includedNotes = new ArrayList<>();
|
||||||
|
}
|
||||||
|
includedNotes.add(IncludedNote.introductionNote(content));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a free text paragraph, which will become an includedNote element with explicit
|
||||||
|
* subjectCode {@link SubjectCode#AAK}
|
||||||
|
*
|
||||||
|
* @param content freeform UTF8 plain text
|
||||||
|
* @return fluent setter
|
||||||
|
*/
|
||||||
|
public Invoice addDiscountBonusNote(String content) {
|
||||||
|
if (includedNotes == null) {
|
||||||
|
includedNotes = new ArrayList<>();
|
||||||
|
}
|
||||||
|
includedNotes.add(IncludedNote.discountBonusNote(content));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* adds a free text paragraph, which will become an includedNote element with explicit
|
|
||||||
* subjectCode {@link SubjectCode#TXD}
|
|
||||||
* @param content freeform UTF8 plain text
|
|
||||||
* @return fluent setter
|
|
||||||
*/
|
|
||||||
public Invoice addTaxNote(String content) {
|
|
||||||
if (includedNotes == null) {
|
|
||||||
includedNotes = new ArrayList<>();
|
|
||||||
}
|
|
||||||
includedNotes.add(IncludedNote.taxNote(content));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* adds a free text paragraph, which will become an includedNote element with explicit
|
|
||||||
* subjectCode {@link SubjectCode#ACY}
|
|
||||||
* @param content freeform UTF8 plain text
|
|
||||||
* @return fluent setter
|
|
||||||
*/
|
|
||||||
public Invoice addIntroductionNote(String content) {
|
|
||||||
if (includedNotes == null) {
|
|
||||||
includedNotes = new ArrayList<>();
|
|
||||||
}
|
|
||||||
includedNotes.add(IncludedNote.introductionNote(content));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* adds a free text paragraph, which will become an includedNote element with explicit
|
|
||||||
* subjectCode {@link SubjectCode#AAK}
|
|
||||||
* @param content freeform UTF8 plain text
|
|
||||||
* @return fluent setter
|
|
||||||
*/
|
|
||||||
public Invoice addDiscountBonusNote(String content) {
|
|
||||||
if (includedNotes == null) {
|
|
||||||
includedNotes = new ArrayList<>();
|
|
||||||
}
|
|
||||||
includedNotes.add(IncludedNote.discountBonusNote(content));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSpecifiedProcuringProjectID() {
|
public String getSpecifiedProcuringProjectID() {
|
||||||
return specifiedProcuringProjectID;
|
return specifiedProcuringProjectID;
|
||||||
@@ -841,6 +914,7 @@ public class Invoice implements IExportableTransaction {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Decide when the VAT should be collected.
|
* Decide when the VAT should be collected.
|
||||||
|
*
|
||||||
* @param vatDueDateTypeCode use EventTimeCodeTypeConstants
|
* @param vatDueDateTypeCode use EventTimeCodeTypeConstants
|
||||||
* @return fluent setter
|
* @return fluent setter
|
||||||
*/
|
*/
|
||||||
@@ -849,4 +923,13 @@ public class Invoice implements IExportableTransaction {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCreditorReferenceID() {
|
||||||
|
return creditorReferenceID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Invoice setCreditorReferenceID(String creditorReferenceID) {
|
||||||
|
this.creditorReferenceID = creditorReferenceID;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package org.mustangproject;
|
package org.mustangproject;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import org.apache.fop.util.XMLUtil;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import org.mustangproject.ZUGFeRD.IReferencedDocument;
|
import org.mustangproject.ZUGFeRD.IReferencedDocument;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
|
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
|
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
|
||||||
|
import org.mustangproject.util.NodeMap;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
@@ -12,24 +13,30 @@ import java.math.BigDecimal;
|
|||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* describes any invoice line
|
* describes any invoice line
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
public class Item implements IZUGFeRDExportableItem {
|
public class Item implements IZUGFeRDExportableItem {
|
||||||
protected BigDecimal price, quantity, tax, grossPrice, lineTotalAmount;
|
protected BigDecimal price = BigDecimal.ZERO;
|
||||||
|
protected BigDecimal quantity;
|
||||||
|
protected BigDecimal tax;
|
||||||
|
protected BigDecimal grossPrice;
|
||||||
|
protected BigDecimal lineTotalAmount;
|
||||||
protected BigDecimal basisQuantity = BigDecimal.ONE;
|
protected BigDecimal basisQuantity = BigDecimal.ONE;
|
||||||
protected Date detailedDeliveryPeriodFrom = null, detailedDeliveryPeriodTo = null;
|
protected Date detailedDeliveryPeriodFrom = null;
|
||||||
|
protected Date detailedDeliveryPeriodTo = null;
|
||||||
protected String id;
|
protected String id;
|
||||||
protected String referencedLineID = null;
|
protected String referencedLineID = null;
|
||||||
protected Product product;
|
protected Product product;
|
||||||
protected ArrayList<String> notes = null;
|
protected ArrayList<String> notes = null;
|
||||||
protected ArrayList<ReferencedDocument> referencedDocuments = null;
|
protected ArrayList<ReferencedDocument> referencedDocuments = null;
|
||||||
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<IZUGFeRDAllowanceCharge>(),
|
protected ArrayList<ReferencedDocument> additionalReference = null;
|
||||||
Charges = new ArrayList<IZUGFeRDAllowanceCharge>();
|
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>();
|
||||||
|
protected ArrayList<IZUGFeRDAllowanceCharge> Charges = new ArrayList<>();
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* default constructor
|
* default constructor
|
||||||
@@ -43,7 +50,6 @@ public class Item implements IZUGFeRDExportableItem {
|
|||||||
this.product = product;
|
this.product = product;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* empty constructor
|
* empty constructor
|
||||||
* do not use, but might be used e.g. by jackson
|
* do not use, but might be used e.g. by jackson
|
||||||
@@ -52,222 +58,75 @@ public class Item implements IZUGFeRDExportableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Item(NodeList itemChilds, boolean recalcPrice) {
|
public Item(NodeList itemChilds, boolean recalcPrice) {
|
||||||
String price = "0";
|
NodeMap itemMap = new NodeMap(itemChilds);
|
||||||
String basisQuantity = "1";
|
|
||||||
String name = "";
|
|
||||||
String sellerAssignedID = null;
|
|
||||||
String description = "";
|
|
||||||
SchemedID gid = null;
|
|
||||||
String quantity = "0";
|
|
||||||
String vatPercent = null;
|
|
||||||
String lineTotal = "0";
|
|
||||||
String unitCode = "0";
|
|
||||||
|
|
||||||
ArrayList<ReferencedDocument> rdocs = null;
|
itemMap.getAsNodeMap("Item").ifPresent(icnm -> {
|
||||||
|
// ubl
|
||||||
|
//we need: name description unitcode
|
||||||
|
//and we additionally have vat%
|
||||||
|
setProduct(new Product());
|
||||||
|
icnm.getAsString("Name").ifPresent(product::setName);
|
||||||
|
icnm.getAsNodeMap("ClassifiedTaxCategory").flatMap(m -> m.getAsBigDecimal("Percent"))
|
||||||
|
.ifPresent(product::setVATPercent);
|
||||||
|
});
|
||||||
|
|
||||||
// nodes.item(i).getTextContent())) {
|
itemMap.getAsNodeMap("Price").ifPresent(icnm -> {
|
||||||
|
// ubl
|
||||||
|
// PriceAmount with currencyID and BaseQuantity with unitCode
|
||||||
|
icnm.getAsBigDecimal("PriceAmount").ifPresent(this::setPrice);
|
||||||
|
icnm.getAsBigDecimal("BaseQuantity").ifPresent(this::setBasisQuantity);
|
||||||
|
});
|
||||||
|
|
||||||
for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) {
|
itemMap.getNode("InvoicedQuantity").ifPresent(icn -> {
|
||||||
String lineTrade = itemChilds.item(itemChildIndex).getLocalName();
|
// ubl
|
||||||
if ((lineTrade != null) && (lineTrade.equals("Item"))) {
|
setQuantity(new BigDecimal(icn.getTextContent().trim()));
|
||||||
// ubl
|
product.setUnit(icn.getAttributes().getNamedItem("unitCode").getNodeValue());
|
||||||
//we need: name description unitcode
|
});
|
||||||
//and we additionally have vat%
|
|
||||||
NodeList UBLitemChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
|
||||||
for (Node currentUBLItemChildNode : XMLTools.asList(UBLitemChilds)) {
|
|
||||||
|
|
||||||
if ((currentUBLItemChildNode.getLocalName() != null) && (currentUBLItemChildNode.getLocalName().equals("Name"))) {
|
itemMap.getAsNodeMap("SpecifiedLineTradeAgreement", "SpecifiedSupplyChainTradeAgreement").ifPresent(icnm -> {
|
||||||
name = currentUBLItemChildNode.getTextContent();
|
icnm.getAsNodeMap("BuyerOrderReferencedDocument")
|
||||||
}
|
.flatMap(bordNodes -> bordNodes.getAsString("LineID"))
|
||||||
if ((currentUBLItemChildNode.getLocalName() != null) && (currentUBLItemChildNode.getLocalName().equals("ClassifiedTaxCategory"))) {
|
.ifPresent(this::addReferencedLineID);
|
||||||
for (Node currentUBLTaxChildNode : XMLTools.asList(currentUBLItemChildNode.getChildNodes())) {
|
|
||||||
if ((currentUBLTaxChildNode.getLocalName() != null) && (currentUBLTaxChildNode.getLocalName().equals("Percent"))) {
|
icnm.getAsNodeMap("NetPriceProductTradePrice").ifPresent(npptpNodes -> {
|
||||||
vatPercent = currentUBLTaxChildNode.getTextContent();
|
npptpNodes.getAsBigDecimal("ChargeAmount").ifPresent(this::setPrice);
|
||||||
}
|
npptpNodes.getAsBigDecimal("BasisQuantity").ifPresent(this::setBasisQuantity);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode)
|
||||||
|
.forEach(this::addReferencedDocument);
|
||||||
|
});
|
||||||
|
|
||||||
|
itemMap.getNode("SpecifiedTradeProduct").map(Product::new).ifPresent(this::setProduct);
|
||||||
|
|
||||||
|
// RequestedQuantity is for Order-X, BilledQuantity for FX and ZF
|
||||||
|
itemMap.getAsNodeMap("SpecifiedLineTradeDelivery", "SpecifiedSupplyChainTradeDelivery")
|
||||||
|
.flatMap(icnm -> icnm.getNode("BilledQuantity", "RequestedQuantity", "DespatchedQuantity"))
|
||||||
|
.ifPresent(bq -> {
|
||||||
|
setQuantity(new BigDecimal(bq.getTextContent().trim()));
|
||||||
|
if (bq.hasAttributes()) {
|
||||||
|
Node unitAttr = bq.getAttributes().getNamedItem("unitCode");
|
||||||
|
if (unitAttr != null) {
|
||||||
|
product.setUnit(unitAttr.getNodeValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
itemMap.getAsNodeMap("SpecifiedLineTradeSettlement", "SpecifiedSupplyChainTradeSettlement").ifPresent(icnm -> {
|
||||||
|
icnm.getAsNodeMap("ApplicableTradeTax")
|
||||||
|
.flatMap(cnm -> cnm.getAsBigDecimal("RateApplicablePercent", "ApplicablePercent"))
|
||||||
|
.ifPresent(product::setVATPercent);
|
||||||
|
|
||||||
|
if (recalcPrice && !BigDecimal.ZERO.equals(quantity)) {
|
||||||
|
icnm.getAsNodeMap("SpecifiedTradeSettlementLineMonetarySummation")
|
||||||
|
.flatMap(cnm -> cnm.getAsBigDecimal("LineTotalAmount"))
|
||||||
|
.ifPresent(lineTotal -> setPrice(lineTotal.divide(quantity, 4, RoundingMode.HALF_UP)));
|
||||||
}
|
}
|
||||||
if ((lineTrade != null) && (lineTrade.equals("Price"))) {
|
|
||||||
// ubl
|
|
||||||
// PriceAmount with currencyID and BaseQuantity with unitCode
|
|
||||||
NodeList UBLpriceChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
|
||||||
for (Node currentUBLPriceChildNode : XMLTools.asList(UBLpriceChilds)) {
|
|
||||||
|
|
||||||
if ((currentUBLPriceChildNode.getLocalName() != null) && (currentUBLPriceChildNode.getLocalName().equals("PriceAmount"))) {
|
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).forEach(this::addAdditionalReference);
|
||||||
price = currentUBLPriceChildNode.getTextContent();
|
});
|
||||||
}
|
|
||||||
if ((currentUBLPriceChildNode.getLocalName() != null) && (currentUBLPriceChildNode.getLocalName().equals("BaseQuantity"))) {
|
|
||||||
basisQuantity = currentUBLPriceChildNode.getTextContent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if ((lineTrade != null) && (lineTrade.equals("InvoicedQuantity"))) {
|
|
||||||
// ubl
|
|
||||||
quantity = itemChilds.item(itemChildIndex).getTextContent();
|
|
||||||
unitCode = itemChilds.item(itemChildIndex).getAttributes()
|
|
||||||
.getNamedItem("unitCode").getNodeValue();
|
|
||||||
}
|
|
||||||
if ((lineTrade != null) && (lineTrade.equals("SpecifiedLineTradeAgreement")
|
|
||||||
|| lineTrade.equals("SpecifiedSupplyChainTradeAgreement"))) {
|
|
||||||
NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
|
||||||
for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds
|
|
||||||
.getLength(); tradeLineChildIndex++) {
|
|
||||||
|
|
||||||
if ((tradeLineChilds.item(tradeLineChildIndex).getLocalName() != null) && tradeLineChilds
|
|
||||||
.item(tradeLineChildIndex).getLocalName().equals("AdditionalReferencedDocument")) {
|
|
||||||
String IssuerAssignedID = "";
|
|
||||||
String TypeCode = "";
|
|
||||||
String ReferenceTypeCode = "";
|
|
||||||
|
|
||||||
NodeList refDocChilds = tradeLineChilds.item(tradeLineChildIndex).getChildNodes();
|
|
||||||
for (int refDocIndex = 0; refDocIndex < refDocChilds.getLength(); refDocIndex++) {
|
|
||||||
String localName = refDocChilds.item(refDocIndex).getLocalName();
|
|
||||||
if ((localName != null) && (localName.equals("IssuerAssignedID"))) {
|
|
||||||
IssuerAssignedID = refDocChilds.item(refDocIndex).getTextContent();
|
|
||||||
}
|
|
||||||
if ((localName != null) && (localName.equals("TypeCode"))) {
|
|
||||||
TypeCode = refDocChilds.item(refDocIndex).getTextContent();
|
|
||||||
}
|
|
||||||
if ((localName != null) && (localName.equals("ReferenceTypeCode"))) {
|
|
||||||
ReferenceTypeCode = refDocChilds.item(refDocIndex).getTextContent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReferencedDocument rd = new ReferencedDocument(IssuerAssignedID, TypeCode,
|
|
||||||
ReferenceTypeCode);
|
|
||||||
if (rdocs == null) {
|
|
||||||
rdocs = new ArrayList<ReferencedDocument>();
|
|
||||||
}
|
|
||||||
rdocs.add(rd);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tradeLineChilds.item(tradeLineChildIndex).getLocalName() != null) && tradeLineChilds
|
|
||||||
.item(tradeLineChildIndex).getLocalName().equals("NetPriceProductTradePrice")) {
|
|
||||||
NodeList netChilds = tradeLineChilds.item(tradeLineChildIndex).getChildNodes();
|
|
||||||
for (int netIndex = 0; netIndex < netChilds.getLength(); netIndex++) {
|
|
||||||
if ((netChilds.item(netIndex).getLocalName() != null)
|
|
||||||
&& (netChilds.item(netIndex).getLocalName().equals("ChargeAmount"))) {
|
|
||||||
price = netChilds.item(netIndex).getTextContent();// ChargeAmount
|
|
||||||
|
|
||||||
}
|
|
||||||
if ((netChilds.item(netIndex).getLocalName() != null)
|
|
||||||
&& ((netChilds.item(netIndex).getLocalName().equals("BasisQuantity")) || (netChilds.item(netIndex).getLocalName().equals("InvoicedQuantity")))) {
|
|
||||||
basisQuantity = netChilds.item(netIndex).getTextContent();// ChargeAmount
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((lineTrade != null) && (lineTrade.equals("SpecifiedLineTradeDelivery")
|
|
||||||
|| lineTrade.equals("SpecifiedSupplyChainTradeDelivery"))) {
|
|
||||||
NodeList tradeLineChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
|
||||||
for (int tradeLineChildIndex = 0; tradeLineChildIndex < tradeLineChilds
|
|
||||||
.getLength(); tradeLineChildIndex++) {
|
|
||||||
String tradeName = tradeLineChilds.item(tradeLineChildIndex).getLocalName();
|
|
||||||
if ((tradeName != null)
|
|
||||||
&& (tradeName.equals("BilledQuantity") || tradeName.equals("RequestedQuantity")
|
|
||||||
|| tradeName.equals("DespatchedQuantity"))) {
|
|
||||||
// RequestedQuantity is for Order-X, BilledQuantity for FX and ZF
|
|
||||||
quantity = tradeLineChilds.item(tradeLineChildIndex).getTextContent();
|
|
||||||
unitCode = tradeLineChilds.item(tradeLineChildIndex).getAttributes()
|
|
||||||
.getNamedItem("unitCode").getNodeValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((lineTrade != null) && (lineTrade.equals("SpecifiedTradeProduct"))) {
|
|
||||||
NodeList tradeProductChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
|
||||||
for (int tradeProductChildIndex = 0; tradeProductChildIndex < tradeProductChilds
|
|
||||||
.getLength(); tradeProductChildIndex++) {
|
|
||||||
if ((tradeProductChilds.item(tradeProductChildIndex).getLocalName() != null)
|
|
||||||
&& (tradeProductChilds.item(tradeProductChildIndex).getLocalName()
|
|
||||||
.equals("Name"))) {
|
|
||||||
name = tradeProductChilds.item(tradeProductChildIndex).getTextContent();
|
|
||||||
}
|
|
||||||
if ((tradeProductChilds.item(tradeProductChildIndex).getLocalName() != null)
|
|
||||||
&& (tradeProductChilds.item(tradeProductChildIndex).getLocalName()
|
|
||||||
.equals("SellerAssignedID"))) {
|
|
||||||
sellerAssignedID = tradeProductChilds.item(tradeProductChildIndex).getTextContent();
|
|
||||||
}
|
|
||||||
if ((tradeProductChilds.item(tradeProductChildIndex).getLocalName() != null)
|
|
||||||
&& (tradeProductChilds.item(tradeProductChildIndex).getLocalName()
|
|
||||||
.equals("GlobalID"))) {
|
|
||||||
if (tradeProductChilds.item(tradeProductChildIndex).getAttributes()
|
|
||||||
.getNamedItem("schemeID") != null) {
|
|
||||||
gid = new SchemedID()
|
|
||||||
.setScheme(tradeProductChilds.item(tradeProductChildIndex).getAttributes()
|
|
||||||
.getNamedItem("schemeID").getNodeValue())
|
|
||||||
.setId(tradeProductChilds.item(tradeProductChildIndex).getTextContent());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((lineTrade != null) && (lineTrade.equals("SpecifiedLineTradeSettlement")
|
|
||||||
|| lineTrade.equals("SpecifiedSupplyChainTradeSettlement"))) {
|
|
||||||
NodeList tradeSettlementChilds = itemChilds.item(itemChildIndex).getChildNodes();
|
|
||||||
for (int tradeSettlementChildIndex = 0; tradeSettlementChildIndex < tradeSettlementChilds
|
|
||||||
.getLength(); tradeSettlementChildIndex++) {
|
|
||||||
|
|
||||||
String tradeSettlementName = tradeSettlementChilds.item(tradeSettlementChildIndex)
|
|
||||||
.getLocalName();
|
|
||||||
if (tradeSettlementName != null) {
|
|
||||||
if (tradeSettlementName.equals("ApplicableTradeTax")) {
|
|
||||||
NodeList taxChilds = tradeSettlementChilds.item(tradeSettlementChildIndex)
|
|
||||||
.getChildNodes();
|
|
||||||
for (int taxChildIndex = 0; taxChildIndex < taxChilds
|
|
||||||
.getLength(); taxChildIndex++) {
|
|
||||||
String taxChildName = taxChilds.item(taxChildIndex).getLocalName();
|
|
||||||
if ((taxChildName != null) && (taxChildName.equals("RateApplicablePercent")
|
|
||||||
|| taxChildName.equals("ApplicablePercent"))) {
|
|
||||||
vatPercent = taxChilds.item(taxChildIndex).getTextContent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tradeSettlementName.equals("SpecifiedTradeSettlementLineMonetarySummation")) {
|
|
||||||
NodeList totalChilds = tradeSettlementChilds.item(tradeSettlementChildIndex)
|
|
||||||
.getChildNodes();
|
|
||||||
for (int totalChildIndex = 0; totalChildIndex < totalChilds
|
|
||||||
.getLength(); totalChildIndex++) {
|
|
||||||
if ((totalChilds.item(totalChildIndex).getLocalName() != null) && (totalChilds
|
|
||||||
.item(totalChildIndex).getLocalName().equals("LineTotalAmount"))) {
|
|
||||||
lineTotal = totalChilds.item(totalChildIndex).getTextContent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BigDecimal prc = new BigDecimal(price.trim());
|
|
||||||
BigDecimal qty = new BigDecimal(quantity.trim());
|
|
||||||
if ((recalcPrice) && (!qty.equals(BigDecimal.ZERO))) {
|
|
||||||
prc = new BigDecimal(lineTotal.trim()).divide(qty, 4, RoundingMode.HALF_UP);
|
|
||||||
}
|
|
||||||
Product p = new Product(name, description, unitCode,
|
|
||||||
vatPercent == null ? null : new BigDecimal(vatPercent.trim()));
|
|
||||||
if (gid != null) {
|
|
||||||
p.addGlobalID(gid);
|
|
||||||
}
|
|
||||||
if (sellerAssignedID != null) {
|
|
||||||
p.setSellerAssignedID(sellerAssignedID);
|
|
||||||
}
|
|
||||||
setProduct(p);
|
|
||||||
setPrice(prc);
|
|
||||||
setQuantity(qty);
|
|
||||||
setBasisQuantity(new BigDecimal(basisQuantity));
|
|
||||||
if (rdocs != null) {
|
|
||||||
for (ReferencedDocument rdoc : rdocs) {
|
|
||||||
addReferencedDocument(rdoc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Item addReferencedLineID(String s) {
|
public Item addReferencedLineID(String s) {
|
||||||
referencedLineID = s;
|
referencedLineID = s;
|
||||||
return this;
|
return this;
|
||||||
@@ -428,7 +287,7 @@ public class Item implements IZUGFeRDExportableItem {
|
|||||||
*/
|
*/
|
||||||
public Item addNote(String text) {
|
public Item addNote(String text) {
|
||||||
if (notes == null) {
|
if (notes == null) {
|
||||||
notes = new ArrayList<String>();
|
notes = new ArrayList<>();
|
||||||
}
|
}
|
||||||
notes.add(text);
|
notes.add(text);
|
||||||
return this;
|
return this;
|
||||||
@@ -441,7 +300,7 @@ public class Item implements IZUGFeRDExportableItem {
|
|||||||
*/
|
*/
|
||||||
public Item addReferencedDocument(ReferencedDocument doc) {
|
public Item addReferencedDocument(ReferencedDocument doc) {
|
||||||
if (referencedDocuments == null) {
|
if (referencedDocuments == null) {
|
||||||
referencedDocuments = new ArrayList<ReferencedDocument>();
|
referencedDocuments = new ArrayList<>();
|
||||||
}
|
}
|
||||||
referencedDocuments.add(doc);
|
referencedDocuments.add(doc);
|
||||||
return this;
|
return this;
|
||||||
@@ -455,6 +314,29 @@ public class Item implements IZUGFeRDExportableItem {
|
|||||||
return referencedDocuments.toArray(new IReferencedDocument[0]);
|
return referencedDocuments.toArray(new IReferencedDocument[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***
|
||||||
|
* adds item level references along with their typecodes and issuerassignedIDs (contract ID, cost centre, ...)
|
||||||
|
* @param doc the ReferencedDocument to add
|
||||||
|
* @return fluent setter
|
||||||
|
*/
|
||||||
|
public Item addAdditionalReference(ReferencedDocument doc) {
|
||||||
|
if (additionalReference == null) {
|
||||||
|
additionalReference = new ArrayList<>();
|
||||||
|
}
|
||||||
|
additionalReference.add(doc);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IReferencedDocument[] getAdditionalReferences() {
|
||||||
|
if (additionalReference == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return additionalReference.toArray(new IReferencedDocument[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* specify a item level delivery period
|
* specify a item level delivery period
|
||||||
* (apart from the document level delivery period, and the document level
|
* (apart from the document level delivery period, and the document level
|
||||||
@@ -475,6 +357,7 @@ public class Item implements IZUGFeRDExportableItem {
|
|||||||
* this will be included in a BillingSpecifiedPeriod element
|
* this will be included in a BillingSpecifiedPeriod element
|
||||||
* @return the beginning of the delivery period
|
* @return the beginning of the delivery period
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Date getDetailedDeliveryPeriodFrom() {
|
public Date getDetailedDeliveryPeriodFrom() {
|
||||||
return detailedDeliveryPeriodFrom;
|
return detailedDeliveryPeriodFrom;
|
||||||
}
|
}
|
||||||
@@ -484,6 +367,7 @@ public class Item implements IZUGFeRDExportableItem {
|
|||||||
* this will be included in a BillingSpecifiedPeriod element
|
* this will be included in a BillingSpecifiedPeriod element
|
||||||
* @return the end of the delivery period
|
* @return the end of the delivery period
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Date getDetailedDeliveryPeriodTo() {
|
public Date getDetailedDeliveryPeriodTo() {
|
||||||
return detailedDeliveryPeriodTo;
|
return detailedDeliveryPeriodTo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,46 +5,74 @@ import org.mustangproject.ZUGFeRD.*;
|
|||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* A organisation, i.e. usually a company
|
* A organisation, i.e. usually a company
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class LegalOrganisation implements IZUGFeRDLegalOrganisation {
|
public class LegalOrganisation implements IZUGFeRDLegalOrganisation {
|
||||||
|
|
||||||
protected String ID = null;
|
protected SchemedID schemedID = null;
|
||||||
protected String SchemeID = null;
|
protected String tradingBusinessName = null;
|
||||||
|
|
||||||
public LegalOrganisation() {
|
public LegalOrganisation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public LegalOrganisation(String ID, String scheme) {
|
public LegalOrganisation(String ID, String scheme) {
|
||||||
this.ID=ID;
|
this.schemedID = new SchemedID(scheme, ID);
|
||||||
this.SchemeID=scheme;
|
}
|
||||||
|
|
||||||
|
public LegalOrganisation(SchemedID schemedID, String tradingBusinessName) {
|
||||||
|
this.schemedID = schemedID;
|
||||||
|
this.tradingBusinessName=tradingBusinessName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* XML parsing constructor
|
||||||
|
* @param nodes the nodelist returned e.g. from xpath
|
||||||
|
*/
|
||||||
|
public LegalOrganisation(NodeList nodes) {
|
||||||
|
if (nodes.getLength() > 0) {
|
||||||
|
/*
|
||||||
|
will parse sth like
|
||||||
|
<ram:SpecifiedLegalOrganization>
|
||||||
|
<ram:ID schemeID="0002">4711</ram:ID>
|
||||||
|
<ram:TradingBusinessName>Test GmbH & Co.KG</ram:TradingBusinessName>
|
||||||
|
</ram:SpecifiedLegalOrganization>
|
||||||
|
*/
|
||||||
|
for (int nodeIndex = 0; nodeIndex < nodes.getLength(); nodeIndex++) {
|
||||||
|
Node currentItemNode = nodes.item(nodeIndex);
|
||||||
|
if (currentItemNode.getLocalName() != null) {
|
||||||
|
if (currentItemNode.getLocalName().equals("GlobalID")) {
|
||||||
|
if (currentItemNode.getAttributes().getNamedItem("schemeID") != null) {
|
||||||
|
SchemedID gid = new SchemedID().setScheme(currentItemNode.getAttributes().getNamedItem("schemeID").getNodeValue()).setId(currentItemNode.getTextContent());
|
||||||
|
this.setSchemedID(gid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentItemNode.getLocalName().equals("TradingBusinessName")) {
|
||||||
|
setTradingBusinessName(currentItemNode.getFirstChild().getNodeValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getID() {
|
public SchemedID getSchemedID() {
|
||||||
return ID;
|
return this.schemedID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSchemeID() {
|
public String getTradingBusinessName() {
|
||||||
return SchemeID;
|
return this.tradingBusinessName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LegalOrganisation setID(String id) {
|
public LegalOrganisation setSchemedID(SchemedID schemedID) {
|
||||||
this.ID=id;
|
this.schemedID = schemedID;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LegalOrganisation setSchemeID(String scheme) {
|
public LegalOrganisation setTradingBusinessName(String tradingBusinessName) {
|
||||||
SchemeID=scheme;
|
this.tradingBusinessName = tradingBusinessName;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,37 @@
|
|||||||
package org.mustangproject;
|
package org.mustangproject;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import org.mustangproject.ZUGFeRD.IDesignatedProductClassification;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct;
|
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct;
|
||||||
|
import org.mustangproject.util.NodeMap;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* describes a product, good or service used in an invoice item line
|
* describes a product, good or service used in an invoice item line
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
|
|
||||||
public class Product implements IZUGFeRDExportableProduct {
|
public class Product implements IZUGFeRDExportableProduct {
|
||||||
protected String unit, name, description, sellerAssignedID, buyerAssignedID;
|
protected String unit, name, sellerAssignedID, buyerAssignedID;
|
||||||
|
protected String description="";
|
||||||
|
protected String taxExemptionReason=null;
|
||||||
|
protected String taxCategoryCode=null;
|
||||||
protected BigDecimal VATPercent;
|
protected BigDecimal VATPercent;
|
||||||
protected boolean isReverseCharge = false;
|
protected boolean isReverseCharge = false;
|
||||||
protected boolean isIntraCommunitySupply = false;
|
protected boolean isIntraCommunitySupply = false;
|
||||||
protected SchemedID globalId = null;
|
protected SchemedID globalId = null;
|
||||||
|
protected String countryOfOrigin = null;
|
||||||
|
protected HashMap<String, String> attributes = new HashMap<>();
|
||||||
|
protected List<IDesignatedProductClassification> classifications = new ArrayList<>();
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* default constructor
|
* default constructor
|
||||||
@@ -30,6 +47,42 @@ public class Product implements IZUGFeRDExportableProduct {
|
|||||||
this.VATPercent = VATPercent;
|
this.VATPercent = VATPercent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Product(Node node) {
|
||||||
|
NodeMap nodeMap = new NodeMap(node);
|
||||||
|
|
||||||
|
nodeMap.getNode("GlobalID").ifPresent(idNode -> {
|
||||||
|
if (idNode.hasAttributes()
|
||||||
|
&& idNode.getAttributes().getNamedItem("schemeID") != null) {
|
||||||
|
globalId = new SchemedID()
|
||||||
|
.setScheme(idNode.getAttributes().getNamedItem("schemeID").getNodeValue())
|
||||||
|
.setId(idNode.getTextContent());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nodeMap.getAsString("SellerAssignedID").ifPresent(this::setSellerAssignedID);
|
||||||
|
nodeMap.getAsString("BuyerAssignedID").ifPresent(this::setBuyerAssignedID);
|
||||||
|
nodeMap.getAsString("Name").ifPresent(this::setName);
|
||||||
|
nodeMap.getAsString("Description").ifPresent(this::setDescription);
|
||||||
|
|
||||||
|
nodeMap.getAsNodeMap("ApplicableProductCharacteristic").ifPresent(apcNodes -> {
|
||||||
|
String key = apcNodes.getAsStringOrNull("Description");
|
||||||
|
String value = apcNodes.getAsStringOrNull("Value");
|
||||||
|
if (key != null && value != null) {
|
||||||
|
if (attributes == null) {
|
||||||
|
attributes = new HashMap<>();
|
||||||
|
}
|
||||||
|
attributes.put(key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nodeMap.getAsNodeMap("DesignatedProductClassification").ifPresent(dpcNodes -> {
|
||||||
|
String className = dpcNodes.getAsStringOrNull("ClassName");
|
||||||
|
dpcNodes.getNode("ClassCode").map(ClassCode::fromNode).ifPresent(classCode ->
|
||||||
|
classifications.add(new DesignatedProductClassification(classCode, className)));
|
||||||
|
});
|
||||||
|
|
||||||
|
nodeMap.getAsString("OriginTradeCounty").ifPresent(this::setCountryOfOrigin);
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* empty constructor
|
* empty constructor
|
||||||
@@ -62,7 +115,49 @@ public class Product implements IZUGFeRDExportableProduct {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* @return e.g. intra-commnunity supply or small business
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getTaxExemptionReason() {
|
||||||
|
return taxExemptionReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* @param taxExemptionReasonText String e.g. Kleinunternehmer gemäß §19 UStG https://github.com/ZUGFeRD/mustangproject/issues/463
|
||||||
|
* @return fluent setter
|
||||||
|
*/
|
||||||
|
public Product setTaxExemptionReason(String taxExemptionReasonText) {
|
||||||
|
taxExemptionReason = taxExemptionReasonText;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* @return e.g. S (normal tax), Z=zero rated, E (e.g. small business) or K (intrra community supply)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getTaxCategoryCode() {
|
||||||
|
if (taxCategoryCode == null) {
|
||||||
|
return IZUGFeRDExportableProduct.super.getTaxCategoryCode();
|
||||||
|
}
|
||||||
|
return taxCategoryCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* @param code e.g. S (normal tax), Z=zero rated, E (e.g. small business) or K (intrra community supply) see also https://github.com/ZUGFeRD/mustangproject/issues/463
|
||||||
|
* @return fluent setter
|
||||||
|
*/
|
||||||
|
public Product setTaxCategoryCode(String code) {
|
||||||
|
taxCategoryCode = code;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getSellerAssignedID() {
|
public String getSellerAssignedID() {
|
||||||
return sellerAssignedID;
|
return sellerAssignedID;
|
||||||
}
|
}
|
||||||
@@ -77,6 +172,7 @@ public class Product implements IZUGFeRDExportableProduct {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getBuyerAssignedID() {
|
public String getBuyerAssignedID() {
|
||||||
return buyerAssignedID;
|
return buyerAssignedID;
|
||||||
}
|
}
|
||||||
@@ -119,6 +215,8 @@ public class Product implements IZUGFeRDExportableProduct {
|
|||||||
public Product setIntraCommunitySupply() {
|
public Product setIntraCommunitySupply() {
|
||||||
isIntraCommunitySupply = true;
|
isIntraCommunitySupply = true;
|
||||||
setVATPercent(BigDecimal.ZERO);
|
setVATPercent(BigDecimal.ZERO);
|
||||||
|
setTaxExemptionReason("Intra-community supply");
|
||||||
|
setTaxCategoryCode("K");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,4 +281,70 @@ public class Product implements IZUGFeRDExportableProduct {
|
|||||||
this.VATPercent = VATPercent;
|
this.VATPercent = VATPercent;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCountryOfOrigin() {
|
||||||
|
return this.countryOfOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Product setCountryOfOrigin(String countryOfOrigin) {
|
||||||
|
this.countryOfOrigin = countryOfOrigin;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashMap<String, String> getAttributes() {
|
||||||
|
if (attributes.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return this.attributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Product setAttributes(Map<String, String> attributes) {
|
||||||
|
this.attributes.clear();
|
||||||
|
if (attributes != null) {
|
||||||
|
this.attributes.putAll(attributes);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Product addAttribute(String name, String value ) {
|
||||||
|
this.attributes.put(name, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IDesignatedProductClassification[] getClassifications() {
|
||||||
|
if (classifications.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return classifications.toArray(new IDesignatedProductClassification[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the current set of {@link IDesignatedProductClassification}s with a new set
|
||||||
|
*
|
||||||
|
* @param classifications the new set of classifications
|
||||||
|
* @return the modified object
|
||||||
|
*/
|
||||||
|
public Product setClassifications(IDesignatedProductClassification[] classifications) {
|
||||||
|
this.classifications.clear();
|
||||||
|
if (classifications != null) {
|
||||||
|
this.classifications.addAll(Arrays.asList(classifications));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a {@link IDesignatedProductClassification} classification
|
||||||
|
*
|
||||||
|
* @param classification the classification
|
||||||
|
* @return the modified object
|
||||||
|
*/
|
||||||
|
public Product addClassification(IDesignatedProductClassification classification) {
|
||||||
|
this.classifications.add(classification);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package org.mustangproject;
|
package org.mustangproject;
|
||||||
|
|
||||||
import org.mustangproject.ZUGFeRD.IReferencedDocument;
|
import org.mustangproject.ZUGFeRD.IReferencedDocument;
|
||||||
|
import org.mustangproject.util.NodeMap;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
public class ReferencedDocument implements IReferencedDocument {
|
public class ReferencedDocument implements IReferencedDocument {
|
||||||
|
|
||||||
@@ -58,4 +60,14 @@ public class ReferencedDocument implements IReferencedDocument {
|
|||||||
public String getReferenceTypeCode() {
|
public String getReferenceTypeCode() {
|
||||||
return referenceTypeCode;
|
return referenceTypeCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ReferencedDocument fromNode(Node node) {
|
||||||
|
if (!node.hasChildNodes()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
NodeMap nodes = new NodeMap(node);
|
||||||
|
return new ReferencedDocument(nodes.getAsStringOrNull("IssuerAssignedID"),
|
||||||
|
nodes.getAsStringOrNull("TypeCode"),
|
||||||
|
nodes.getAsStringOrNull("ReferenceTypeCode"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,4 +31,9 @@ public class SchemedID {
|
|||||||
setId(id);
|
setId(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SchemedID{scheme='" + scheme + "', id='" + id + "'}";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,29 +5,32 @@ import java.util.List;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact;
|
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTradeParty;
|
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTradeParty;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDLegalOrganisation;
|
import org.mustangproject.ZUGFeRD.IZUGFeRDLegalOrganisation;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlement;
|
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlement;
|
||||||
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlementDebit;
|
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* A organisation, i.e. usually a company
|
* A organisation, i.e. usually a company
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
public class TradeParty implements IZUGFeRDExportableTradeParty {
|
public class TradeParty implements IZUGFeRDExportableTradeParty {
|
||||||
|
|
||||||
protected String name, zip, street, location, country;
|
protected String name, zip, street, location, country;
|
||||||
protected String taxID = null, vatID = null;
|
protected String taxID = null, vatID = null;
|
||||||
protected String ID = null;
|
protected String ID = null;
|
||||||
|
protected String description = null;
|
||||||
protected String additionalAddress = null;
|
protected String additionalAddress = null;
|
||||||
protected String additionalAddressExtension = null;
|
protected String additionalAddressExtension = null;
|
||||||
protected List<BankDetails> bankDetails = new ArrayList<>();
|
protected List<BankDetails> bankDetails = new ArrayList<>();
|
||||||
protected List<IZUGFeRDTradeSettlementDebit> debitDetails = new ArrayList<>();
|
protected List<DirectDebit> debitDetails = new ArrayList<>();
|
||||||
protected Contact contact = null;
|
protected Contact contact = null;
|
||||||
protected LegalOrganisation legalOrg = null;
|
protected LegalOrganisation legalOrg = null;
|
||||||
protected SchemedID globalId = null;
|
protected SchemedID globalId = null;
|
||||||
@@ -66,15 +69,15 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
//nodes.item(i).getTextContent())) {
|
//nodes.item(i).getTextContent())) {
|
||||||
Node currentItemNode = nodes.item(nodeIndex);
|
Node currentItemNode = nodes.item(nodeIndex);
|
||||||
|
|
||||||
if (nodes.item(nodeIndex).getLocalName() != null) {
|
if (currentItemNode.getLocalName() != null) {
|
||||||
String debcurrentChild = nodes.item(nodeIndex).getLocalName();
|
String currentUBLChild = currentItemNode.getLocalName();
|
||||||
if (nodes.item(nodeIndex).getLocalName().equals("Party")) {
|
if (currentUBLChild.equals("Party")) {
|
||||||
|
|
||||||
NodeList party = nodes.item(nodeIndex).getChildNodes();
|
NodeList party = currentItemNode.getChildNodes();
|
||||||
for (int partyIndex = 0; partyIndex < party.getLength(); partyIndex++) {
|
for (int partyIndex = 0; partyIndex < party.getLength(); partyIndex++) {
|
||||||
if (party.item(partyIndex).getLocalName() != null) {
|
if (party.item(partyIndex).getLocalName() != null) {
|
||||||
String debCN = party.item(partyIndex).getLocalName();
|
String currentTopElementName = party.item(partyIndex).getLocalName();
|
||||||
if (party.item(partyIndex).getLocalName().equals("PartyName")) {
|
if (currentTopElementName.equals("PartyName")) {
|
||||||
|
|
||||||
NodeList partyName = party.item(partyIndex).getChildNodes();
|
NodeList partyName = party.item(partyIndex).getChildNodes();
|
||||||
for (int partyNameIndex = 0; partyNameIndex < partyName.getLength(); partyNameIndex++) {
|
for (int partyNameIndex = 0; partyNameIndex < partyName.getLength(); partyNameIndex++) {
|
||||||
@@ -87,7 +90,20 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (party.item(partyIndex).getLocalName().equals("PostalAddress")) {
|
|
||||||
|
// UBL only: formally it can have a name as well but BT27 party name *should* be stored in
|
||||||
|
// so overwrite if one exists
|
||||||
|
if (currentTopElementName.equals("PartyLegalEntity")) {
|
||||||
|
NodeList legal = party.item(partyIndex).getChildNodes();
|
||||||
|
for (int legalChildIndex = 0; legalChildIndex < legal.getLength(); legalChildIndex++) {
|
||||||
|
if (legal.item(legalChildIndex).getLocalName() != null) {
|
||||||
|
if (legal.item(legalChildIndex).getLocalName().equals("RegistrationName")) {
|
||||||
|
setName(legal.item(legalChildIndex).getTextContent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentTopElementName.equals("PostalAddress")) {
|
||||||
|
|
||||||
NodeList postal = party.item(partyIndex).getChildNodes();
|
NodeList postal = party.item(partyIndex).getChildNodes();
|
||||||
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
|
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
|
||||||
@@ -145,7 +161,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (party.item(partyIndex).getLocalName().equals("Contact")) {
|
if (currentTopElementName.equals("Contact")) {
|
||||||
NodeList contact = party.item(partyIndex).getChildNodes();
|
NodeList contact = party.item(partyIndex).getChildNodes();
|
||||||
setContact(new Contact(contact));
|
setContact(new Contact(contact));
|
||||||
|
|
||||||
@@ -156,19 +172,19 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodes.item(nodeIndex).getLocalName().equals("GlobalID")) {
|
if (currentUBLChild.equals("GlobalID")) {
|
||||||
if (nodes.item(nodeIndex).getAttributes().getNamedItem("schemeID") != null) {
|
if (nodes.item(nodeIndex).getAttributes().getNamedItem("schemeID") != null) {
|
||||||
SchemedID gid = new SchemedID().setScheme(nodes.item(nodeIndex).getAttributes().getNamedItem("schemeID").getNodeValue()).setId(nodes.item(nodeIndex).getTextContent());
|
SchemedID gid = new SchemedID().setScheme(nodes.item(nodeIndex).getAttributes().getNamedItem("schemeID").getNodeValue()).setId(nodes.item(nodeIndex).getTextContent());
|
||||||
addGlobalID(gid);
|
addGlobalID(gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (nodes.item(nodeIndex).getLocalName().equals("DefinedTradeContact")) {
|
if (currentUBLChild.equals("DefinedTradeContact")) {
|
||||||
NodeList contact = nodes.item(nodeIndex).getChildNodes();
|
NodeList contact = nodes.item(nodeIndex).getChildNodes();
|
||||||
setContact(new Contact(contact));
|
setContact(new Contact(contact));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodes.item(nodeIndex).getLocalName().equals("PostalTradeAddress")) {
|
if (currentUBLChild.equals("PostalTradeAddress")) {
|
||||||
NodeList postal = nodes.item(nodeIndex).getChildNodes();
|
NodeList postal = nodes.item(nodeIndex).getChildNodes();
|
||||||
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
|
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
|
||||||
if (postal.item(postalChildIndex).getLocalName() != null) {
|
if (postal.item(postalChildIndex).getLocalName() != null) {
|
||||||
@@ -196,7 +212,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodes.item(nodeIndex).getLocalName().equals("SpecifiedTaxRegistration")) {
|
if (currentUBLChild.equals("SpecifiedTaxRegistration")) {
|
||||||
NodeList taxChilds = nodes.item(nodeIndex).getChildNodes();
|
NodeList taxChilds = nodes.item(nodeIndex).getChildNodes();
|
||||||
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
|
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
|
||||||
if (taxChilds.item(taxChildIndex).getLocalName() != null) {
|
if (taxChilds.item(taxChildIndex).getLocalName() != null) {
|
||||||
@@ -204,12 +220,10 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID") != null) {
|
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID") != null) {
|
||||||
Node firstChild = taxChilds.item(taxChildIndex).getFirstChild();
|
Node firstChild = taxChilds.item(taxChildIndex).getFirstChild();
|
||||||
if (firstChild != null) {
|
if (firstChild != null) {
|
||||||
if (taxChilds.item(taxChildIndex).getAttributes()
|
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("VA")) {
|
||||||
.getNamedItem("schemeID").getNodeValue().equals("VA")) {
|
|
||||||
setVATID(firstChild.getNodeValue());
|
setVATID(firstChild.getNodeValue());
|
||||||
}
|
}
|
||||||
if (taxChilds.item(taxChildIndex).getAttributes()
|
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("FC")) {
|
||||||
.getNamedItem("schemeID").getNodeValue().equals("FC")) {
|
|
||||||
setTaxID(firstChild.getNodeValue());
|
setTaxID(firstChild.getNodeValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -289,8 +303,8 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
|
|
||||||
for (int nodeIndex = 0; nodeIndex < nodes.getLength(); nodeIndex++) {
|
for (int nodeIndex = 0; nodeIndex < nodes.getLength(); nodeIndex++) {
|
||||||
//nodes.item(i).getTextContent())) {
|
//nodes.item(i).getTextContent())) {
|
||||||
String debLN = nodes.item(nodeIndex).getLocalName();
|
String topElementName = nodes.item(nodeIndex).getLocalName();
|
||||||
if (nodes.item(nodeIndex).getLocalName().equals("Party")) {
|
if (topElementName.equals("Party")) {
|
||||||
// take one step back and parse from top
|
// take one step back and parse from top
|
||||||
parseFromUBL(nodes);
|
parseFromUBL(nodes);
|
||||||
return;
|
return;
|
||||||
@@ -299,15 +313,26 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
NodeList itemChilds = currentItemNode.getChildNodes();
|
NodeList itemChilds = currentItemNode.getChildNodes();
|
||||||
for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) {
|
for (int itemChildIndex = 0; itemChildIndex < itemChilds.getLength(); itemChildIndex++) {
|
||||||
if (itemChilds.item(itemChildIndex).getLocalName() != null) {
|
if (itemChilds.item(itemChildIndex).getLocalName() != null) {
|
||||||
|
if (itemChilds.item(itemChildIndex).getLocalName().equals("ID")) {
|
||||||
|
setID(itemChilds.item(itemChildIndex).getTextContent());
|
||||||
|
}
|
||||||
if (itemChilds.item(itemChildIndex).getLocalName().equals("Name")) {
|
if (itemChilds.item(itemChildIndex).getLocalName().equals("Name")) {
|
||||||
setName(itemChilds.item(itemChildIndex).getTextContent());
|
setName(itemChilds.item(itemChildIndex).getTextContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (itemChilds.item(itemChildIndex).getLocalName().equals("Description")) {
|
||||||
|
setDescription(itemChilds.item(itemChildIndex).getTextContent());
|
||||||
|
}
|
||||||
if (itemChilds.item(itemChildIndex).getLocalName().equals("GlobalID")) {
|
if (itemChilds.item(itemChildIndex).getLocalName().equals("GlobalID")) {
|
||||||
if (itemChilds.item(itemChildIndex).getAttributes().getNamedItem("schemeID") != null) {
|
if (itemChilds.item(itemChildIndex).getAttributes().getNamedItem("schemeID") != null) {
|
||||||
SchemedID gid = new SchemedID().setScheme(itemChilds.item(itemChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue()).setId(itemChilds.item(itemChildIndex).getTextContent());
|
SchemedID gid = new SchemedID().setScheme(itemChilds.item(itemChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue()).setId(itemChilds.item(itemChildIndex).getTextContent());
|
||||||
addGlobalID(gid);
|
addGlobalID(gid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (itemChilds.item(itemChildIndex).getLocalName().equals("SpecifiedLegalOrganization")) {
|
||||||
|
NodeList organization = itemChilds.item(itemChildIndex).getChildNodes();
|
||||||
|
setLegalOrganisation(new LegalOrganisation(organization));
|
||||||
|
}
|
||||||
if (itemChilds.item(itemChildIndex).getLocalName().equals("DefinedTradeContact")) {
|
if (itemChilds.item(itemChildIndex).getLocalName().equals("DefinedTradeContact")) {
|
||||||
NodeList contact = itemChilds.item(itemChildIndex).getChildNodes();
|
NodeList contact = itemChilds.item(itemChildIndex).getChildNodes();
|
||||||
setContact(new Contact(contact));
|
setContact(new Contact(contact));
|
||||||
@@ -359,12 +384,10 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID") != null) {
|
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID") != null) {
|
||||||
Node firstChild = taxChilds.item(taxChildIndex).getFirstChild();
|
Node firstChild = taxChilds.item(taxChildIndex).getFirstChild();
|
||||||
if (firstChild != null) {
|
if (firstChild != null) {
|
||||||
if (taxChilds.item(taxChildIndex).getAttributes()
|
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("VA")) {
|
||||||
.getNamedItem("schemeID").getNodeValue().equals("VA")) {
|
|
||||||
setVATID(firstChild.getNodeValue());
|
setVATID(firstChild.getNodeValue());
|
||||||
}
|
}
|
||||||
if (taxChilds.item(taxChildIndex).getAttributes()
|
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("FC")) {
|
||||||
.getNamedItem("schemeID").getNodeValue().equals("FC")) {
|
|
||||||
setTaxID(firstChild.getNodeValue());
|
setTaxID(firstChild.getNodeValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -404,6 +427,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
public String getUriUniversalCommunicationID() {
|
public String getUriUniversalCommunicationID() {
|
||||||
if (uriUniversalCommunicationId != null) {
|
if (uriUniversalCommunicationId != null) {
|
||||||
return uriUniversalCommunicationId.getID();
|
return uriUniversalCommunicationId.getID();
|
||||||
@@ -413,6 +437,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
public String getUriUniversalCommunicationIDScheme() {
|
public String getUriUniversalCommunicationIDScheme() {
|
||||||
if (uriUniversalCommunicationId != null) {
|
if (uriUniversalCommunicationId != null) {
|
||||||
return uriUniversalCommunicationId.getScheme();
|
return uriUniversalCommunicationId.getScheme();
|
||||||
@@ -423,8 +448,9 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* sets the email of the organization (not the one of the contact person)
|
* sets the email of the organization (not the one of the contact person)
|
||||||
* (while setEmail has to be defined here getEmail comes from IZUGFeRDExportableTradeParty)
|
* (while setEmail has to be defined here getEmail comes from IZUGFeRDExportableTradeParty)
|
||||||
|
* @param eMail address of institution (not contact)
|
||||||
* @return fluent setter
|
* @return fluent setter
|
||||||
*/
|
*/
|
||||||
public TradeParty setEmail(String eMail) {
|
public TradeParty setEmail(String eMail) {
|
||||||
@@ -476,17 +502,26 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (optional)
|
* (optional)
|
||||||
*
|
*
|
||||||
* @param debitDetail e.g. containing IBAN and mandate
|
* @param debitDetail e.g. containing IBAN and mandate
|
||||||
* @return fluent setter
|
* @return fluent setter
|
||||||
*/
|
*/
|
||||||
public TradeParty addDebitDetails(IZUGFeRDTradeSettlementDebit debitDetail) {
|
public TradeParty addDebitDetails(DirectDebit debitDetail) {
|
||||||
debitDetails.add(debitDetail);
|
debitDetails.add(debitDetail);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* primarily for invoiceimporter and JSON
|
||||||
|
* @return the list of sepa mandates
|
||||||
|
*/
|
||||||
|
public List<DirectDebit> getDebitDetails() {
|
||||||
|
return debitDetails;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IZUGFeRDLegalOrganisation getLegalOrganisation() {
|
public IZUGFeRDLegalOrganisation getLegalOrganisation() {
|
||||||
return legalOrg;
|
return legalOrg;
|
||||||
@@ -557,6 +592,26 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* @return String the description, e.g. if it's a vat exempt company
|
||||||
|
*/
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***
|
||||||
|
* required, usually done in the constructor: the complete name of the organisation
|
||||||
|
* @param description human readable description
|
||||||
|
* @return fluent setter
|
||||||
|
*/
|
||||||
|
public TradeParty setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getZIP() {
|
public String getZIP() {
|
||||||
return zip;
|
return zip;
|
||||||
}
|
}
|
||||||
@@ -626,13 +681,12 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
|
|||||||
return contact;
|
return contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public IZUGFeRDTradeSettlement[] getAsTradeSettlement() {
|
public IZUGFeRDTradeSettlement[] getAsTradeSettlement() {
|
||||||
if (bankDetails.isEmpty() && debitDetails.isEmpty()) {
|
if (bankDetails.isEmpty() && debitDetails.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
List<IZUGFeRDTradeSettlement> tradeSettlements = Stream.concat(bankDetails.stream(), debitDetails.stream())
|
List<IZUGFeRDTradeSettlement> tradeSettlements = Stream.concat(bankDetails.stream(), debitDetails.stream()).map(IZUGFeRDTradeSettlement.class::cast).collect(Collectors.toList());
|
||||||
.map(IZUGFeRDTradeSettlement.class::cast)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
IZUGFeRDTradeSettlement[] result = new IZUGFeRDTradeSettlement[tradeSettlements.size()];
|
IZUGFeRDTradeSettlement[] result = new IZUGFeRDTradeSettlement[tradeSettlements.size()];
|
||||||
for (int i = 0; i < tradeSettlements.size(); i++) {
|
for (int i = 0; i < tradeSettlements.size(); i++) {
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
package org.mustangproject;
|
package org.mustangproject;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.util.AbstractList;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Collections;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
import java.util.RandomAccess;
|
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.dom4j.io.XMLWriter;
|
import org.dom4j.io.XMLWriter;
|
||||||
|
import org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
|
|
||||||
public class XMLTools extends XMLWriter {
|
public class XMLTools extends XMLWriter {
|
||||||
@Override
|
@Override
|
||||||
@@ -24,34 +21,11 @@ public class XMLTools extends XMLWriter {
|
|||||||
@Override
|
@Override
|
||||||
public String escapeElementEntities(String s) {
|
public String escapeElementEntities(String s) {
|
||||||
return super.escapeElementEntities(s);
|
return super.escapeElementEntities(s);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Node> asList(NodeList n) {
|
|
||||||
return n.getLength() == 0 ?
|
|
||||||
Collections.<Node>emptyList() : new NodeListWrapper(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class NodeListWrapper extends AbstractList<Node>
|
|
||||||
implements RandomAccess {
|
|
||||||
private final NodeList list;
|
|
||||||
|
|
||||||
NodeListWrapper(NodeList l) {
|
|
||||||
list = l;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node get(int index) {
|
|
||||||
return list.item(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size() {
|
|
||||||
return list.getLength();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String nDigitFormat(BigDecimal value, int scale) {
|
public static String nDigitFormat(BigDecimal value, int scale) {
|
||||||
/*
|
/*
|
||||||
* I needed 123,45, locale independent.I tried
|
* I needed 123.45, locale independent.I tried
|
||||||
* NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is locale
|
* NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is locale
|
||||||
* specific.I also tried DecimalFormat df = new DecimalFormat( "0,00" );
|
* specific.I also tried DecimalFormat df = new DecimalFormat( "0,00" );
|
||||||
* df.setDecimalSeparatorAlwaysShown(true); df.setGroupingUsed(false);
|
* df.setDecimalSeparatorAlwaysShown(true); df.setGroupingUsed(false);
|
||||||
@@ -69,7 +43,105 @@ public class XMLTools extends XMLWriter {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the value of an node
|
||||||
|
*
|
||||||
|
* @param node the Node to get the value from
|
||||||
|
* @return A String or empty String, if no value was found
|
||||||
|
*/
|
||||||
|
public static String getNodeValue(Node node) {
|
||||||
|
if (node != null && node.getFirstChild() != null) {
|
||||||
|
return node.getFirstChild().getNodeValue();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tries to convert a String to BigDecimal.
|
||||||
|
*
|
||||||
|
* @param nodeValue The value as String
|
||||||
|
* @return a BigDecimal with the value provides as String or a BigDecimal with value 0.00 if an error occurs
|
||||||
|
*/
|
||||||
|
public static BigDecimal tryBigDecimal(String nodeValue) {
|
||||||
|
try {
|
||||||
|
return new BigDecimal(nodeValue);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
try {
|
||||||
|
return BigDecimal.valueOf(Float.valueOf(nodeValue));
|
||||||
|
} catch (final Exception ex) {
|
||||||
|
return new BigDecimal("0.00");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tries to convert a Node to a BigDecimal.
|
||||||
|
*
|
||||||
|
* @param node The value as String
|
||||||
|
* @return a BigDecimal with the value provides as String or a BigDecimal with value 0.00 if an error occurs
|
||||||
|
*/
|
||||||
|
public static BigDecimal tryBigDecimal(Node node) {
|
||||||
|
final String nodeValue = XMLTools.getNodeValue(node);
|
||||||
|
if (nodeValue.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return XMLTools.tryBigDecimal(nodeValue);
|
||||||
|
}
|
||||||
|
/***
|
||||||
|
* formats a number so that at least minDecimals are displayed but at the maximum maxDecimals are there, i.e.
|
||||||
|
* cuts potential 0s off the end until minDecimals
|
||||||
|
* @param value
|
||||||
|
* @param maxDecimals number of maximal scale
|
||||||
|
* @param minDecimals number of minimal scale
|
||||||
|
* @return value as String with decimals in the specified range
|
||||||
|
*/
|
||||||
|
public static String nDigitFormatDecimalRange(BigDecimal value, int maxDecimals, int minDecimals) {
|
||||||
|
if ((maxDecimals<minDecimals)||(maxDecimals<0)||(minDecimals<0)) {
|
||||||
|
throw new IllegalArgumentException("Invalid scale range provided");
|
||||||
|
}
|
||||||
|
int curDecimals=maxDecimals;
|
||||||
|
while ( (curDecimals>minDecimals) && (value.setScale(curDecimals, RoundingMode.HALF_UP).compareTo(value.setScale(curDecimals-1, RoundingMode.HALF_UP))==0)) {
|
||||||
|
curDecimals--;
|
||||||
|
}
|
||||||
|
return value.setScale(curDecimals, RoundingMode.HALF_UP).toPlainString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***
|
||||||
|
* returns a util.Date from a 102 String yyyymmdd in a node
|
||||||
|
* @param node the node
|
||||||
|
* @return a util.Date, or null, if not parseable
|
||||||
|
*/
|
||||||
|
public static Date tryDate(Node node) {
|
||||||
|
final String nodeValue = XMLTools.getNodeValue(node);
|
||||||
|
if (nodeValue.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tryDate(nodeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* returns a util.Date from a 102 String yyyymmdd
|
||||||
|
* @param toParse the string
|
||||||
|
* @return a util.Date, or null, if not parseable
|
||||||
|
*/
|
||||||
|
public static Date tryDate(String toParse) {
|
||||||
|
final SimpleDateFormat formatter = ZUGFeRDDateFormat.DATE.getFormatter();
|
||||||
|
try {
|
||||||
|
return formatter.parse(toParse);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* relplaces some entities like < , > and & with their escaped pendant like <
|
||||||
|
* @param s the string
|
||||||
|
* @return the "safe" string
|
||||||
|
*/
|
||||||
public static String encodeXML(CharSequence s) {
|
public static String encodeXML(CharSequence s) {
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
return "";
|
return "";
|
||||||
@@ -120,36 +192,6 @@ public class XMLTools extends XMLWriter {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Byte Order Mark size and thus allows to skips over a BOM
|
|
||||||
* at the beginning of the given ByteArrayInputStream, if one exists.
|
|
||||||
*
|
|
||||||
* @param is the ByteArrayInputStream used
|
|
||||||
* @throws IOException if can not be read from is
|
|
||||||
* @see <a href="https://www.w3.org/TR/xml/#sec-guessing">Autodetection of Character Encodings</a>
|
|
||||||
*
|
|
||||||
public static int guessBOMSize(ByteArrayInputStream is) throws IOException {
|
|
||||||
byte[] pad = new byte[4];
|
|
||||||
is.read(pad);
|
|
||||||
is.reset();
|
|
||||||
int test2 = ((pad[0] & 0xFF) << 8) | (pad[1] & 0xFF);
|
|
||||||
int test3 = ((test2 & 0xFFFF) << 8) | (pad[2] & 0xFF);
|
|
||||||
int test4 = ((test3 & 0xFFFFFF) << 8) | (pad[3] & 0xFF);
|
|
||||||
//
|
|
||||||
if (test4 == 0x0000FEFF || test4 == 0xFFFE0000 || test4 == 0x0000FFFE || test4 == 0xFEFF0000) {
|
|
||||||
// UCS-4: BOM takes 4 bytes
|
|
||||||
return 4;
|
|
||||||
} else if (test3 == 0xEFBBFF) {
|
|
||||||
// UTF-8: BOM takes 3 bytes
|
|
||||||
return 3;
|
|
||||||
} else if (test2 == 0xFEFF || test2 == 0xFFFE) {
|
|
||||||
// UTF-16: BOM takes 2 bytes
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* removes utf8 byte order marks from byte arrays, in case one is there
|
* removes utf8 byte order marks from byte arrays, in case one is there
|
||||||
* @param zugferdRaw the CII XML
|
* @param zugferdRaw the CII XML
|
||||||
@@ -157,6 +199,7 @@ public class XMLTools extends XMLWriter {
|
|||||||
*/
|
*/
|
||||||
public static byte[] removeBOM(byte[] zugferdRaw) {
|
public static byte[] removeBOM(byte[] zugferdRaw) {
|
||||||
final byte[] zugferdData;
|
final byte[] zugferdData;
|
||||||
|
// This handles the UTF-8 BOM
|
||||||
if ((zugferdRaw[0] == (byte) 0xEF) && (zugferdRaw[1] == (byte) 0xBB) && (zugferdRaw[2] == (byte) 0xBF)) {
|
if ((zugferdRaw[0] == (byte) 0xEF) && (zugferdRaw[1] == (byte) 0xBB) && (zugferdRaw[2] == (byte) 0xBF)) {
|
||||||
// I don't like BOMs, lets remove it
|
// I don't like BOMs, lets remove it
|
||||||
zugferdData = new byte[zugferdRaw.length - 3];
|
zugferdData = new byte[zugferdRaw.length - 3];
|
||||||
@@ -168,20 +211,19 @@ public class XMLTools extends XMLWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] getBytesFromStream(InputStream fileinput) throws IOException {
|
public static byte[] getBytesFromStream(InputStream fileinput) throws IOException {
|
||||||
|
return IOUtils.toByteArray (fileinput);
|
||||||
// we're on java 8 so we cant use inputstream.readallbytes
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
int nRead;
|
|
||||||
byte[] data = new byte[16384];
|
|
||||||
BufferedInputStream bufferedInput=new BufferedInputStream(fileinput);
|
|
||||||
|
|
||||||
while ((nRead = bufferedInput.read(data, 0, data.length)) != -1) {
|
|
||||||
buffer.write(data, 0, nRead);
|
|
||||||
}
|
|
||||||
return buffer.toByteArray();
|
|
||||||
|
|
||||||
// end of polyfill
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String trimOrNull(Node node) {
|
||||||
|
if (node != null) {
|
||||||
|
String textContent = node.getTextContent();
|
||||||
|
if (textContent != null) {
|
||||||
|
return textContent.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,18 +22,18 @@ package org.mustangproject.ZUGFeRD;
|
|||||||
|
|
||||||
import static org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat.DATE;
|
import static org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat.DATE;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.mustangproject.*;
|
import org.mustangproject.EStandard;
|
||||||
|
import org.mustangproject.FileAttachment;
|
||||||
|
import org.mustangproject.Invoice;
|
||||||
|
import org.mustangproject.XMLTools;
|
||||||
|
|
||||||
public class DAPullProvider extends ZUGFeRD2PullProvider implements IXMLProvider {
|
public class DAPullProvider extends ZUGFeRD2PullProvider {
|
||||||
|
|
||||||
protected IExportableTransaction trans;
|
protected IExportableTransaction trans;
|
||||||
private String paymentTermsDescription;
|
|
||||||
protected Profile profile = Profiles.getByName(EStandard.despatchadvice,"pilot", 1);
|
protected Profile profile = Profiles.getByName(EStandard.despatchadvice,"pilot", 1);
|
||||||
|
|
||||||
|
|
||||||
@@ -249,13 +249,9 @@ public class DAPullProvider extends ZUGFeRD2PullProvider implements IXMLProvider
|
|||||||
+ "</SCRDMCCBDACIDAMessageStructure>";
|
+ "</SCRDMCCBDACIDAMessageStructure>";
|
||||||
|
|
||||||
final byte[] zugferdRaw;
|
final byte[] zugferdRaw;
|
||||||
try {
|
zugferdRaw = xml.getBytes(StandardCharsets.UTF_8);
|
||||||
zugferdRaw = xml.getBytes("UTF-8");
|
|
||||||
|
|
||||||
zugferdData = XMLTools.removeBOM(zugferdRaw);
|
zugferdData = XMLTools.removeBOM(zugferdRaw);
|
||||||
} catch (final UnsupportedEncodingException e) {
|
|
||||||
Logger.getLogger(OXPullProvider.class.getName()).log(Level.SEVERE, null, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,31 +19,35 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
|
||||||
import org.apache.pdfbox.preflight.PreflightDocument;
|
|
||||||
import org.apache.pdfbox.preflight.exception.ValidationException;
|
|
||||||
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
public class DXExporterFromA1 extends DXExporterFromA3 implements IZUGFeRDExporter {
|
import org.apache.pdfbox.preflight.PreflightDocument;
|
||||||
|
import org.apache.pdfbox.preflight.ValidationResult;
|
||||||
|
import org.apache.pdfbox.preflight.exception.ValidationException;
|
||||||
|
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
||||||
|
|
||||||
|
import jakarta.activation.DataSource;
|
||||||
|
|
||||||
|
public class DXExporterFromA1 extends DXExporterFromA3 {
|
||||||
protected boolean ignorePDFAErrors = false;
|
protected boolean ignorePDFAErrors = false;
|
||||||
|
|
||||||
public DXExporterFromA1 ignorePDFAErrors() {
|
@Override
|
||||||
|
public DXExporterFromA1 ignorePDFAErrors() {
|
||||||
this.ignorePDFAErrors = true;
|
this.ignorePDFAErrors = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isValidA1(DataSource dataSource) throws IOException {
|
private static boolean isValidA1(DataSource dataSource) throws IOException {
|
||||||
return getPDFAParserValidationResult(new PreflightParser(dataSource));
|
return getPDFAParserValidationResult(PreflightParserHelper.createPreflightParser (dataSource));
|
||||||
}
|
}
|
||||||
/***
|
/***
|
||||||
* internal helper function: get namespace for order-x
|
* internal helper function: get namespace for order-x
|
||||||
* @param ver the delivery-x version
|
* @param ver the delivery-x version
|
||||||
* @return the URN of the namespace
|
* @return the URN of the namespace
|
||||||
*/
|
*/
|
||||||
public String getNamespaceForVersion(int ver) {
|
@Override
|
||||||
|
public String getNamespaceForVersion(int ver) {
|
||||||
// As of late 2022 the Delivery-X standard is not yet published. See specification:
|
// As of late 2022 the Delivery-X standard is not yet published. See specification:
|
||||||
// Die digitale Ablösung des Papier-Lieferscheins, Version 1.1, April 2022
|
// Die digitale Ablösung des Papier-Lieferscheins, Version 1.1, April 2022
|
||||||
// Chapter 7.1 XMP-Erweiterungsschema für PDF/A-3
|
// Chapter 7.1 XMP-Erweiterungsschema für PDF/A-3
|
||||||
@@ -55,7 +59,8 @@ public class DXExporterFromA1 extends DXExporterFromA3 implements IZUGFeRDExport
|
|||||||
* @param ver the ox version
|
* @param ver the ox version
|
||||||
* @return the namespace prefix as string, without colon
|
* @return the namespace prefix as string, without colon
|
||||||
*/
|
*/
|
||||||
public String getPrefixForVersion(int ver) {
|
@Override
|
||||||
|
public String getPrefixForVersion(int ver) {
|
||||||
return "fx";
|
return "fx";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,19 +70,19 @@ public class DXExporterFromA1 extends DXExporterFromA3 implements IZUGFeRDExport
|
|||||||
* NonSequentialParser. Some additional controls are present to check a set of
|
* NonSequentialParser. Some additional controls are present to check a set of
|
||||||
* PDF/A requirements. (Stream length consistency, EOL after some Keyword...)
|
* PDF/A requirements. (Stream length consistency, EOL after some Keyword...)
|
||||||
*/
|
*/
|
||||||
parser.parse();// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
|
// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
|
||||||
|
|
||||||
try (PreflightDocument document = parser.getPreflightDocument()) {
|
try (PreflightDocument document = (PreflightDocument) parser.parse()) {
|
||||||
/*
|
/*
|
||||||
* Once the syntax validation is done, the parser can provide a
|
* Once the syntax validation is done, the parser can provide a
|
||||||
* PreflightDocument (that inherits from PDDocument) This document process the
|
* PreflightDocument (that inherits from PDDocument) This document process the
|
||||||
* end of PDF/A validation.
|
* end of PDF/A validation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
document.validate();
|
ValidationResult res = document.validate();
|
||||||
|
|
||||||
// Get validation result
|
// Get validation result
|
||||||
return document.getResult().isValid();
|
return res.isValid();
|
||||||
} catch (ValidationException e) {
|
} catch (ValidationException e) {
|
||||||
/*
|
/*
|
||||||
* the parse method can throw a SyntaxValidationException if the PDF file can't
|
* the parse method can throw a SyntaxValidationException if the PDF file can't
|
||||||
@@ -89,14 +94,17 @@ public class DXExporterFromA1 extends DXExporterFromA3 implements IZUGFeRDExport
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public DXExporterFromA1 setProfile(Profile p) {
|
@Override
|
||||||
|
public DXExporterFromA1 setProfile(Profile p) {
|
||||||
return (DXExporterFromA1)super.setProfile(p);
|
return (DXExporterFromA1)super.setProfile(p);
|
||||||
}
|
}
|
||||||
public DXExporterFromA1 setProfile(String profileName) {
|
@Override
|
||||||
|
public DXExporterFromA1 setProfile(String profileName) {
|
||||||
return (DXExporterFromA1)super.setProfile(profileName);
|
return (DXExporterFromA1)super.setProfile(profileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
|
@Override
|
||||||
|
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
|
||||||
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
|
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
|
||||||
throw new IOException("File is not a valid PDF/A input file");
|
throw new IOException("File is not a valid PDF/A input file");
|
||||||
}
|
}
|
||||||
@@ -108,32 +116,41 @@ public class DXExporterFromA1 extends DXExporterFromA3 implements IZUGFeRDExport
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DXExporterFromA1 load(String pdfFilename) throws IOException {
|
@Override
|
||||||
|
public DXExporterFromA1 load(String pdfFilename) throws IOException {
|
||||||
return (DXExporterFromA1) super.load(pdfFilename);
|
return (DXExporterFromA1) super.load(pdfFilename);
|
||||||
}
|
}
|
||||||
public DXExporterFromA1 load(byte[] pdfBinary) throws IOException {
|
@Override
|
||||||
|
public DXExporterFromA1 load(byte[] pdfBinary) throws IOException {
|
||||||
return (DXExporterFromA1) super.load(pdfBinary);
|
return (DXExporterFromA1) super.load(pdfBinary);
|
||||||
}
|
}
|
||||||
public DXExporterFromA1 load(InputStream pdfSource) throws IOException{
|
@Override
|
||||||
|
public DXExporterFromA1 load(InputStream pdfSource) throws IOException{
|
||||||
return (DXExporterFromA1) super.load(pdfSource);
|
return (DXExporterFromA1) super.load(pdfSource);
|
||||||
}
|
}
|
||||||
public DXExporterFromA1 setCreator(String creator) {
|
@Override
|
||||||
|
public DXExporterFromA1 setCreator(String creator) {
|
||||||
return (DXExporterFromA1) super.setCreator(creator);
|
return (DXExporterFromA1) super.setCreator(creator);
|
||||||
}
|
}
|
||||||
public DXExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
@Override
|
||||||
|
public DXExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
||||||
return (DXExporterFromA1) super.setConformanceLevel(newLevel);
|
return (DXExporterFromA1) super.setConformanceLevel(newLevel);
|
||||||
}
|
}
|
||||||
public DXExporterFromA1 setProducer(String producer){
|
@Override
|
||||||
|
public DXExporterFromA1 setProducer(String producer){
|
||||||
return (DXExporterFromA1) super.setProducer(producer);
|
return (DXExporterFromA1) super.setProducer(producer);
|
||||||
}
|
}
|
||||||
public DXExporterFromA1 setZUGFeRDVersion(int version){
|
@Override
|
||||||
|
public DXExporterFromA1 setZUGFeRDVersion(int version){
|
||||||
return (DXExporterFromA1) super.setZUGFeRDVersion(version);
|
return (DXExporterFromA1) super.setZUGFeRDVersion(version);
|
||||||
}
|
}
|
||||||
public DXExporterFromA1 setXML(byte[] zugferdData) throws IOException{
|
@Override
|
||||||
|
public DXExporterFromA1 setXML(byte[] zugferdData) throws IOException{
|
||||||
return (DXExporterFromA1) super.setXML(zugferdData);
|
return (DXExporterFromA1) super.setXML(zugferdData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DXExporterFromA1 disableAutoClose(boolean disableAutoClose){
|
@Override
|
||||||
|
public DXExporterFromA1 disableAutoClose(boolean disableAutoClose){
|
||||||
return (DXExporterFromA1) super.disableAutoClose(disableAutoClose);
|
return (DXExporterFromA1) super.disableAutoClose(disableAutoClose);
|
||||||
}
|
}
|
||||||
public DXExporterFromA1 convertOnly() {
|
public DXExporterFromA1 convertOnly() {
|
||||||
|
|||||||
@@ -20,16 +20,38 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import org.apache.pdfbox.cos.*;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
|
import org.apache.pdfbox.cos.COSArray;
|
||||||
|
import org.apache.pdfbox.cos.COSBase;
|
||||||
|
import org.apache.pdfbox.cos.COSDictionary;
|
||||||
|
import org.apache.pdfbox.cos.COSName;
|
||||||
|
import org.apache.pdfbox.cos.COSObject;
|
||||||
import org.apache.pdfbox.io.IOUtils;
|
import org.apache.pdfbox.io.IOUtils;
|
||||||
import org.apache.pdfbox.pdmodel.*;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
||||||
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo;
|
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo;
|
||||||
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
|
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
|
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
|
||||||
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
|
|
||||||
import org.apache.xmpbox.XMPMetadata;
|
import org.apache.xmpbox.XMPMetadata;
|
||||||
import org.apache.xmpbox.schema.AdobePDFSchema;
|
import org.apache.xmpbox.schema.AdobePDFSchema;
|
||||||
import org.apache.xmpbox.schema.DublinCoreSchema;
|
import org.apache.xmpbox.schema.DublinCoreSchema;
|
||||||
@@ -43,16 +65,13 @@ import org.apache.xmpbox.xml.XmpSerializer;
|
|||||||
import org.mustangproject.EStandard;
|
import org.mustangproject.EStandard;
|
||||||
import org.mustangproject.FileAttachment;
|
import org.mustangproject.FileAttachment;
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
import jakarta.activation.DataSource;
|
||||||
import javax.activation.FileDataSource;
|
import jakarta.activation.FileDataSource;
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
||||||
|
|
||||||
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
||||||
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<FileAttachment>();
|
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This flag controls whether or not the metadata is overwritten, or kind of merged.
|
* This flag controls whether or not the metadata is overwritten, or kind of merged.
|
||||||
@@ -108,9 +127,6 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
protected String despatchAdviceDocumentType = "DESPATCHADVICE";
|
protected String despatchAdviceDocumentType = "DESPATCHADVICE";
|
||||||
|
|
||||||
|
|
||||||
private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
|
|
||||||
|
|
||||||
|
|
||||||
private boolean attachZUGFeRDHeaders = true;
|
private boolean attachZUGFeRDHeaders = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,7 +135,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
*
|
*
|
||||||
* @param pdfFilename filename of an PDF/A1 compliant document
|
* @param pdfFilename filename of an PDF/A1 compliant document
|
||||||
*/
|
*/
|
||||||
public DXExporterFromA3 load(String pdfFilename) throws IOException {
|
@Override
|
||||||
|
public DXExporterFromA3 load(String pdfFilename) throws IOException {
|
||||||
|
|
||||||
ensurePDFIsValid(new FileDataSource(pdfFilename));
|
ensurePDFIsValid(new FileDataSource(pdfFilename));
|
||||||
try (FileInputStream pdf = new FileInputStream(pdfFilename)) {
|
try (FileInputStream pdf = new FileInputStream(pdfFilename)) {
|
||||||
@@ -127,11 +144,13 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IXMLProvider getProvider() {
|
@Override
|
||||||
|
public IXMLProvider getProvider() {
|
||||||
return xmlProvider;
|
return xmlProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DXExporterFromA3 setProfile(Profile p) {
|
@Override
|
||||||
|
public DXExporterFromA3 setProfile(Profile p) {
|
||||||
this.profile = p;
|
this.profile = p;
|
||||||
if (xmlProvider != null) {
|
if (xmlProvider != null) {
|
||||||
xmlProvider.setProfile(p);
|
xmlProvider.setProfile(p);
|
||||||
@@ -139,7 +158,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DXExporterFromA3 setProfile(String profilename) {
|
@Override
|
||||||
|
public DXExporterFromA3 setProfile(String profilename) {
|
||||||
this.profile = Profiles.getByName(profilename);
|
this.profile = Profiles.getByName(profilename);
|
||||||
|
|
||||||
if (xmlProvider != null) {
|
if (xmlProvider != null) {
|
||||||
@@ -148,7 +168,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DXExporterFromA3 addAdditionalFile(String name, byte[] content) {
|
@Override
|
||||||
|
public DXExporterFromA3 addAdditionalFile(String name, byte[] content) {
|
||||||
fileAttachments.add(new FileAttachment(name, "text/xml", "Supplement", content).setDescription("ZUGFeRD extension/additional data"));
|
fileAttachments.add(new FileAttachment(name, "text/xml", "Supplement", content).setDescription("ZUGFeRD extension/additional data"));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -161,9 +182,10 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
*
|
*
|
||||||
* @param pdfBinary binary of a PDF/A1 compliant document
|
* @param pdfBinary binary of a PDF/A1 compliant document
|
||||||
*/
|
*/
|
||||||
public DXExporterFromA3 load(byte[] pdfBinary) throws IOException {
|
@Override
|
||||||
|
public DXExporterFromA3 load(byte[] pdfBinary) throws IOException {
|
||||||
ensurePDFIsValid(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
|
ensurePDFIsValid(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
|
||||||
doc = PDDocument.load(pdfBinary);
|
doc = Loader.loadPDF(pdfBinary);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,11 +193,13 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void attachFile(FileAttachment file) {
|
@Override
|
||||||
|
public void attachFile(FileAttachment file) {
|
||||||
fileAttachments.add(file);
|
fileAttachments.add(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void attachFile(String filename, byte[] data, String mimetype, String relation) {
|
@Override
|
||||||
|
public void attachFile(String filename, byte[] data, String mimetype, String relation) {
|
||||||
FileAttachment fa = new FileAttachment(filename, mimetype, relation, data);
|
FileAttachment fa = new FileAttachment(filename, mimetype, relation, data);
|
||||||
fileAttachments.add(fa);
|
fileAttachments.add(fa);
|
||||||
}
|
}
|
||||||
@@ -185,7 +209,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* @param ZUGFeRDfilename the pdf file name
|
* @param ZUGFeRDfilename the pdf file name
|
||||||
* @throws IOException if anything is wrong in the target location
|
* @throws IOException if anything is wrong in the target location
|
||||||
*/
|
*/
|
||||||
public void export(String ZUGFeRDfilename) throws IOException {
|
@Override
|
||||||
|
public void export(String ZUGFeRDfilename) throws IOException {
|
||||||
if (!documentPrepared) {
|
if (!documentPrepared) {
|
||||||
prepareDocument();
|
prepareDocument();
|
||||||
}
|
}
|
||||||
@@ -212,7 +237,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* @param output the OutputStream
|
* @param output the OutputStream
|
||||||
* @throws IOException if anything is wrong in the OutputStream
|
* @throws IOException if anything is wrong in the OutputStream
|
||||||
*/
|
*/
|
||||||
public void export(OutputStream output) throws IOException {
|
@Override
|
||||||
|
public void export(OutputStream output) throws IOException {
|
||||||
if (!documentPrepared) {
|
if (!documentPrepared) {
|
||||||
prepareDocument();
|
prepareDocument();
|
||||||
}
|
}
|
||||||
@@ -238,7 +264,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* @param data the binary data of the file/attachment
|
* @param data the binary data of the file/attachment
|
||||||
* @throws IOException if anything is wrong with filename
|
* @throws IOException if anything is wrong with filename
|
||||||
*/
|
*/
|
||||||
public void PDFAttachGenericFile(String filename, String relationship, String description,
|
@Override
|
||||||
|
public void PDFAttachGenericFile(String filename, String relationship, String description,
|
||||||
String subType, byte[] data) throws IOException {
|
String subType, byte[] data) throws IOException {
|
||||||
PDFAttachGenericFile(this.doc, filename, relationship, description, subType, data);
|
PDFAttachGenericFile(this.doc, filename, relationship, description, subType, data);
|
||||||
}
|
}
|
||||||
@@ -255,7 +282,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* @param data the binary data of the file/attachment
|
* @param data the binary data of the file/attachment
|
||||||
* @throws IOException if anything is wrong with filename
|
* @throws IOException if anything is wrong with filename
|
||||||
*/
|
*/
|
||||||
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
|
@Override
|
||||||
|
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
|
||||||
String subType, byte[] data) throws IOException {
|
String subType, byte[] data) throws IOException {
|
||||||
fileAttached = true;
|
fileAttached = true;
|
||||||
|
|
||||||
@@ -274,7 +302,7 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
ef.setSize(data.length);
|
ef.setSize(data.length);
|
||||||
ef.setCreationDate(new GregorianCalendar());
|
ef.setCreationDate(new GregorianCalendar());
|
||||||
|
|
||||||
ef.setModDate(GregorianCalendar.getInstance());
|
ef.setModDate(Calendar.getInstance());
|
||||||
|
|
||||||
fs.setEmbeddedFile(ef);
|
fs.setEmbeddedFile(ef);
|
||||||
|
|
||||||
@@ -306,7 +334,7 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
doc.getDocumentCatalog().setNames(names);
|
doc.getDocumentCatalog().setNames(names);
|
||||||
|
|
||||||
// AF entry (Array) in catalog with the FileSpec
|
// AF entry (Array) in catalog with the FileSpec
|
||||||
COSBase AFEntry = (COSBase) doc.getDocumentCatalog().getCOSObject().getItem("AF");
|
COSBase AFEntry = doc.getDocumentCatalog().getCOSObject().getItem("AF");
|
||||||
if ((AFEntry == null)) {
|
if ((AFEntry == null)) {
|
||||||
COSArray cosArray = new COSArray();
|
COSArray cosArray = new COSArray();
|
||||||
cosArray.add(fs);
|
cosArray.add(fs);
|
||||||
@@ -332,7 +360,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* @param zugferdData XML data to be set as a byte array (XML file in raw form).
|
* @param zugferdData XML data to be set as a byte array (XML file in raw form).
|
||||||
* @throws IOException (should not happen)
|
* @throws IOException (should not happen)
|
||||||
*/
|
*/
|
||||||
public DXExporterFromA3 setXML(byte[] zugferdData) throws IOException {
|
@Override
|
||||||
|
public DXExporterFromA3 setXML(byte[] zugferdData) throws IOException {
|
||||||
CustomXMLProvider cus = new CustomXMLProvider();
|
CustomXMLProvider cus = new CustomXMLProvider();
|
||||||
// As of late 2022 the Delivery-X standard is not yet published. See specification:
|
// As of late 2022 the Delivery-X standard is not yet published. See specification:
|
||||||
// Die digitale Ablösung des Papier-Lieferscheins, Version 1.1, April 2022
|
// Die digitale Ablösung des Papier-Lieferscheins, Version 1.1, April 2022
|
||||||
@@ -353,11 +382,13 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
*
|
*
|
||||||
* @param pdfSource source to read a PDF/A1 compliant document from
|
* @param pdfSource source to read a PDF/A1 compliant document from
|
||||||
*/
|
*/
|
||||||
public DXExporterFromA3 load(InputStream pdfSource) throws IOException {
|
@Override
|
||||||
|
public DXExporterFromA3 load(InputStream pdfSource) throws IOException {
|
||||||
return load(readAllBytes(pdfSource));
|
return load(readAllBytes(pdfSource));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
|
@Override
|
||||||
|
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,23 +411,27 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* <p>
|
* <p>
|
||||||
* Feel free to pass "A" as new level if you know what you are doing :-)
|
* Feel free to pass "A" as new level if you know what you are doing :-)
|
||||||
*/
|
*/
|
||||||
public DXExporterFromA3 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
@Override
|
||||||
|
public DXExporterFromA3 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
||||||
conformanceLevel = newLevel;
|
conformanceLevel = newLevel;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public DXExporterFromA3 setCreator(String creator) {
|
@Override
|
||||||
|
public DXExporterFromA3 setCreator(String creator) {
|
||||||
this.creator = creator;
|
this.creator = creator;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DXExporterFromA3 setCreatorTool(String creatorTool) {
|
@Override
|
||||||
|
public DXExporterFromA3 setCreatorTool(String creatorTool) {
|
||||||
this.creatorTool = creatorTool;
|
this.creatorTool = creatorTool;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DXExporterFromA3 setProducer(String producer) {
|
@Override
|
||||||
|
public DXExporterFromA3 setProducer(String producer) {
|
||||||
this.producer = producer;
|
this.producer = producer;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -415,7 +450,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DXExporterFromA3 setAttachZUGFeRDHeaders(boolean attachHeaders) {
|
@Override
|
||||||
|
protected DXExporterFromA3 setAttachZUGFeRDHeaders(boolean attachHeaders) {
|
||||||
this.attachZUGFeRDHeaders = attachHeaders;
|
this.attachZUGFeRDHeaders = attachHeaders;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -428,7 +464,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
*
|
*
|
||||||
* @param metadata the PDFbox XMPMetadata object
|
* @param metadata the PDFbox XMPMetadata object
|
||||||
*/
|
*/
|
||||||
protected void addXMP(XMPMetadata metadata) {
|
@Override
|
||||||
|
protected void addXMP(XMPMetadata metadata) {
|
||||||
|
|
||||||
if (attachZUGFeRDHeaders) {
|
if (attachZUGFeRDHeaders) {
|
||||||
// As of late 2022 the Delivery-X standard is not yet published. See specification:
|
// As of late 2022 the Delivery-X standard is not yet published. See specification:
|
||||||
@@ -459,12 +496,14 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
|
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
|
||||||
* @throws IOException if anything is wrong with already loaded PDF
|
* @throws IOException if anything is wrong with already loaded PDF
|
||||||
*/
|
*/
|
||||||
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
|
@Override
|
||||||
|
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
|
||||||
this.trans = trans;
|
this.trans = trans;
|
||||||
return prepare();
|
return prepare();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExporter prepare() throws IOException {
|
@Override
|
||||||
|
public IExporter prepare() throws IOException {
|
||||||
prepareDocument();
|
prepareDocument();
|
||||||
xmlProvider.generateXML(trans);
|
xmlProvider.generateXML(trans);
|
||||||
String filename = "cida.xml";
|
String filename = "cida.xml";
|
||||||
@@ -483,7 +522,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* Reads the XMPMetadata from the PDDocument, if it exists.
|
* Reads the XMPMetadata from the PDDocument, if it exists.
|
||||||
* Otherwise creates XMPMetadata.
|
* Otherwise creates XMPMetadata.
|
||||||
*/
|
*/
|
||||||
protected XMPMetadata getXmpMetadata() throws IOException {
|
@Override
|
||||||
|
protected XMPMetadata getXmpMetadata() throws IOException {
|
||||||
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
|
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
|
||||||
if ((meta != null) && (meta.getLength() > 0)) {
|
if ((meta != null) && (meta.getLength() > 0)) {
|
||||||
try {
|
try {
|
||||||
@@ -496,7 +536,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return XMPMetadata.createXMPMetadata();
|
return XMPMetadata.createXMPMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
|
@Override
|
||||||
|
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
new XmpSerializer().serialize(xmpMetadata, buffer, true); // see https://github.com/ZUGFeRD/mustangproject/issues/44
|
new XmpSerializer().serialize(xmpMetadata, buffer, true); // see https://github.com/ZUGFeRD/mustangproject/issues/44
|
||||||
return buffer.toByteArray();
|
return buffer.toByteArray();
|
||||||
@@ -506,7 +547,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* Sets the producer if the overwrite flag is set or the producer is not already set.
|
* Sets the producer if the overwrite flag is set or the producer is not already set.
|
||||||
* Sets the PDFVersion to 1.4 if the field is empty.
|
* Sets the PDFVersion to 1.4 if the field is empty.
|
||||||
*/
|
*/
|
||||||
protected void writeAdobePDFSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected void writeAdobePDFSchema(XMPMetadata xmp) {
|
||||||
AdobePDFSchema pdf = getAdobePDFSchema(xmp);
|
AdobePDFSchema pdf = getAdobePDFSchema(xmp);
|
||||||
if (overwrite || isEmpty(pdf.getProducer()))
|
if (overwrite || isEmpty(pdf.getProducer()))
|
||||||
pdf.setProducer(producer);
|
pdf.setProducer(producer);
|
||||||
@@ -516,7 +558,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* Returns the AdobePDFSchema from the XMPMetadata if it exists.
|
* Returns the AdobePDFSchema from the XMPMetadata if it exists.
|
||||||
* If the overwrite flag is set or no AdobePDFSchema exists in the XMPMetadata, it is created, added and returned.
|
* If the overwrite flag is set or no AdobePDFSchema exists in the XMPMetadata, it is created, added and returned.
|
||||||
*/
|
*/
|
||||||
protected AdobePDFSchema getAdobePDFSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected AdobePDFSchema getAdobePDFSchema(XMPMetadata xmp) {
|
||||||
AdobePDFSchema pdf = xmp.getAdobePDFSchema();
|
AdobePDFSchema pdf = xmp.getAdobePDFSchema();
|
||||||
if (pdf != null)
|
if (pdf != null)
|
||||||
if (overwrite)
|
if (overwrite)
|
||||||
@@ -526,7 +569,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return xmp.createAndAddAdobePDFSchema();
|
return xmp.createAndAddAdobePDFSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writePDFAIdentificationSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected void writePDFAIdentificationSchema(XMPMetadata xmp) {
|
||||||
PDFAIdentificationSchema pdfaid = getPDFAIdentificationSchema(xmp);
|
PDFAIdentificationSchema pdfaid = getPDFAIdentificationSchema(xmp);
|
||||||
if (overwrite || isEmpty(pdfaid.getConformance())) {
|
if (overwrite || isEmpty(pdfaid.getConformance())) {
|
||||||
try {
|
try {
|
||||||
@@ -541,17 +585,19 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
pdfaid.setPart(3);
|
pdfaid.setPart(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PDFAIdentificationSchema getPDFAIdentificationSchema(XMPMetadata xmp) {
|
@Override
|
||||||
PDFAIdentificationSchema pdfaid = xmp.getPDFIdentificationSchema();
|
protected PDFAIdentificationSchema getPDFAIdentificationSchema(XMPMetadata xmp) {
|
||||||
|
PDFAIdentificationSchema pdfaid = xmp.getPDFAIdentificationSchema();
|
||||||
if (pdfaid != null)
|
if (pdfaid != null)
|
||||||
if (overwrite)
|
if (overwrite)
|
||||||
xmp.removeSchema(pdfaid);
|
xmp.removeSchema(pdfaid);
|
||||||
else
|
else
|
||||||
return pdfaid;
|
return pdfaid;
|
||||||
return xmp.createAndAddPFAIdentificationSchema();
|
return xmp.createAndAddPDFAIdentificationSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeDublinCoreSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected void writeDublinCoreSchema(XMPMetadata xmp) {
|
||||||
DublinCoreSchema dc = getDublinCoreSchema(xmp);
|
DublinCoreSchema dc = getDublinCoreSchema(xmp);
|
||||||
if (dc.getFormat() == null)
|
if (dc.getFormat() == null)
|
||||||
dc.setFormat("application/pdf");
|
dc.setFormat("application/pdf");
|
||||||
@@ -574,7 +620,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DublinCoreSchema getDublinCoreSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected DublinCoreSchema getDublinCoreSchema(XMPMetadata xmp) {
|
||||||
DublinCoreSchema dc = xmp.getDublinCoreSchema();
|
DublinCoreSchema dc = xmp.getDublinCoreSchema();
|
||||||
if (dc != null)
|
if (dc != null)
|
||||||
if (overwrite)
|
if (overwrite)
|
||||||
@@ -584,15 +631,17 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return xmp.createAndAddDublinCoreSchema();
|
return xmp.createAndAddDublinCoreSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeXMLBasicSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected void writeXMLBasicSchema(XMPMetadata xmp) {
|
||||||
XMPBasicSchema xsb = getXmpBasicSchema(xmp);
|
XMPBasicSchema xsb = getXmpBasicSchema(xmp);
|
||||||
if (overwrite || isEmpty(xsb.getCreatorTool()) || "UnknownApplication".equals(xsb.getCreatorTool()))
|
if (overwrite || isEmpty(xsb.getCreatorTool()) || "UnknownApplication".equals(xsb.getCreatorTool()))
|
||||||
xsb.setCreatorTool(creatorTool);
|
xsb.setCreatorTool(creatorTool);
|
||||||
if (overwrite || xsb.getCreateDate() == null)
|
if (overwrite || xsb.getCreateDate() == null)
|
||||||
xsb.setCreateDate(GregorianCalendar.getInstance());
|
xsb.setCreateDate(Calendar.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected XMPBasicSchema getXmpBasicSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected XMPBasicSchema getXmpBasicSchema(XMPMetadata xmp) {
|
||||||
XMPBasicSchema xsb = xmp.getXMPBasicSchema();
|
XMPBasicSchema xsb = xmp.getXMPBasicSchema();
|
||||||
if (xsb != null)
|
if (xsb != null)
|
||||||
if (overwrite)
|
if (overwrite)
|
||||||
@@ -602,7 +651,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return xmp.createAndAddXMPBasicSchema();
|
return xmp.createAndAddXMPBasicSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeDocumentInformation() {
|
@Override
|
||||||
|
protected void writeDocumentInformation() {
|
||||||
String fullProducer = producer + " (via mustangproject.org " + Version.VERSION + ")";
|
String fullProducer = producer + " (via mustangproject.org " + Version.VERSION + ")";
|
||||||
PDDocumentInformation info = doc.getDocumentInformation();
|
PDDocumentInformation info = doc.getDocumentInformation();
|
||||||
if (overwrite || info.getCreationDate() == null)
|
if (overwrite || info.getCreationDate() == null)
|
||||||
@@ -624,7 +674,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
/**
|
/**
|
||||||
* Adds an OutputIntent and the sRGB color profile if no OutputIntent exist
|
* Adds an OutputIntent and the sRGB color profile if no OutputIntent exist
|
||||||
*/
|
*/
|
||||||
protected void addSRGBOutputIntend() throws IOException {
|
@Override
|
||||||
|
protected void addSRGBOutputIntend() throws IOException {
|
||||||
if (!doc.getDocumentCatalog().getOutputIntents().isEmpty()) {
|
if (!doc.getDocumentCatalog().getOutputIntents().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -647,7 +698,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
/**
|
/**
|
||||||
* Adds a MarkInfo element to the PDF if it doesn't already exist and sets it as marked.
|
* Adds a MarkInfo element to the PDF if it doesn't already exist and sets it as marked.
|
||||||
*/
|
*/
|
||||||
protected void setMarked() {
|
@Override
|
||||||
|
protected void setMarked() {
|
||||||
PDDocumentCatalog catalog = doc.getDocumentCatalog();
|
PDDocumentCatalog catalog = doc.getDocumentCatalog();
|
||||||
if (catalog.getMarkInfo() == null) {
|
if (catalog.getMarkInfo() == null) {
|
||||||
catalog.setMarkInfo(new PDMarkInfo(doc.getPages().getCOSObject()));
|
catalog.setMarkInfo(new PDMarkInfo(doc.getPages().getCOSObject()));
|
||||||
@@ -658,7 +710,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
/**
|
/**
|
||||||
* Adds a StructureTreeRoot element to the PDF if it doesn't already exist.
|
* Adds a StructureTreeRoot element to the PDF if it doesn't already exist.
|
||||||
*/
|
*/
|
||||||
protected void addStructureTreeRoot() {
|
@Override
|
||||||
|
protected void addStructureTreeRoot() {
|
||||||
if (doc.getDocumentCatalog().getStructureTreeRoot() == null) {
|
if (doc.getDocumentCatalog().getStructureTreeRoot() == null) {
|
||||||
doc.getDocumentCatalog().setStructureTreeRoot(new PDStructureTreeRoot());
|
doc.getDocumentCatalog().setStructureTreeRoot(new PDStructureTreeRoot());
|
||||||
}
|
}
|
||||||
@@ -668,19 +721,22 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
/**
|
/**
|
||||||
* @return if pdf file will be automatically closed after adding ZF
|
* @return if pdf file will be automatically closed after adding ZF
|
||||||
*/
|
*/
|
||||||
public boolean isAutoCloseDisabled() {
|
@Override
|
||||||
|
public boolean isAutoCloseDisabled() {
|
||||||
return disableAutoClose;
|
return disableAutoClose;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param disableAutoClose prevent PDF file from being closed after adding ZF
|
* @param disableAutoClose prevent PDF file from being closed after adding ZF
|
||||||
*/
|
*/
|
||||||
public DXExporterFromA3 disableAutoClose(boolean disableAutoClose) {
|
@Override
|
||||||
|
public DXExporterFromA3 disableAutoClose(boolean disableAutoClose) {
|
||||||
this.disableAutoClose = disableAutoClose;
|
this.disableAutoClose = disableAutoClose;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setXMLProvider(IXMLProvider p) {
|
@Override
|
||||||
|
protected void setXMLProvider(IXMLProvider p) {
|
||||||
this.xmlProvider = p;
|
this.xmlProvider = p;
|
||||||
if (profile != null) {
|
if (profile != null) {
|
||||||
xmlProvider.setProfile(profile);
|
xmlProvider.setProfile(profile);
|
||||||
|
|||||||
@@ -20,31 +20,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import org.apache.pdfbox.cos.*;
|
import java.io.File;
|
||||||
import org.apache.pdfbox.io.IOUtils;
|
import java.io.FileOutputStream;
|
||||||
import org.apache.pdfbox.pdmodel.*;
|
import java.io.IOException;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
import java.io.OutputStream;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
|
||||||
import org.apache.pdfbox.preflight.PreflightDocument;
|
|
||||||
import org.apache.pdfbox.preflight.exception.ValidationException;
|
|
||||||
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
|
||||||
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
|
|
||||||
import org.apache.xmpbox.XMPMetadata;
|
|
||||||
import org.apache.xmpbox.schema.AdobePDFSchema;
|
|
||||||
import org.apache.xmpbox.schema.DublinCoreSchema;
|
|
||||||
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
|
|
||||||
import org.apache.xmpbox.schema.XMPBasicSchema;
|
|
||||||
import org.apache.xmpbox.type.BadFieldValueException;
|
|
||||||
import org.apache.xmpbox.xml.XmpSerializer;
|
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
|
||||||
import javax.activation.FileDataSource;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class EinLieferscheinExporter implements IExporter {
|
public class EinLieferscheinExporter implements IExporter {
|
||||||
IXMLProvider xmlProvider;
|
IXMLProvider xmlProvider;
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* *********************************************************************
|
||||||
|
* <p>
|
||||||
|
* Copyright (c) 2024 Jan N. Klug
|
||||||
|
* <p>
|
||||||
|
* Use is subject to license terms.
|
||||||
|
* <p>
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy
|
||||||
|
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
* <p>
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* <p>
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* <p>
|
||||||
|
* **********************************************************************
|
||||||
|
*/
|
||||||
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
import org.mustangproject.ClassCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A product classification that allows to describe a product. Classification codes are schemed by the available systems in UNTDID 7143.
|
||||||
|
*/
|
||||||
|
public interface IDesignatedProductClassification {
|
||||||
|
/**
|
||||||
|
* Classification code
|
||||||
|
*
|
||||||
|
* @return the classification code
|
||||||
|
*/
|
||||||
|
ClassCode getClassCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an optional, human-readable description of the classifcation code
|
||||||
|
*
|
||||||
|
* @return the name or {@code null} if not set
|
||||||
|
*/
|
||||||
|
default String getClassName() { return null; }
|
||||||
|
}
|
||||||
@@ -140,6 +140,11 @@ public interface IExportableTransaction {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default IZUGFeRDCashDiscount[] getCashDiscounts() { return null; }
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @return the invoice line items with the positions
|
||||||
|
*/
|
||||||
IZUGFeRDExportableItem[] getZFItems();
|
IZUGFeRDExportableItem[] getZFItems();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -445,11 +450,19 @@ public interface IExportableTransaction {
|
|||||||
*
|
*
|
||||||
* @return the IZUGFeRDExportableTradeParty delivery address
|
* @return the IZUGFeRDExportableTradeParty delivery address
|
||||||
*/
|
*/
|
||||||
|
|
||||||
default IZUGFeRDExportableTradeParty getDeliveryAddress() {
|
default IZUGFeRDExportableTradeParty getDeliveryAddress() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* payee / payment receiver, if different from seller, ram:Payee (only supported for zf2)
|
||||||
|
*
|
||||||
|
* @return the IZUGFeRDExportableTradeParty payment receiver, if different from sellver
|
||||||
|
*/
|
||||||
|
default IZUGFeRDExportableTradeParty getPayee() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* specifies the document level delivery period, will be included in a
|
* specifies the document level delivery period, will be included in a
|
||||||
* BillingSpecifiedPeriod element
|
* BillingSpecifiedPeriod element
|
||||||
@@ -517,4 +530,7 @@ public interface IExportableTransaction {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default String getCreditorReferenceID() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
*********************************************************************** */
|
*********************************************************************** */
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interface for allowances or charges, to be used by the pullprovider
|
* The interface for allowances or charges, to be used by the pullprovider
|
||||||
* @author AlexanderSchmidt
|
* @author AlexanderSchmidt
|
||||||
@@ -44,6 +44,12 @@ public interface IZUGFeRDAllowanceCharge {
|
|||||||
*/
|
*/
|
||||||
String getReason();
|
String getReason();
|
||||||
|
|
||||||
|
/***
|
||||||
|
* get the code for the allowance/charge
|
||||||
|
* @return the code
|
||||||
|
*/
|
||||||
|
String getReasonCode();
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* get the applicable tax percentage for the allowance/charge
|
* get the applicable tax percentage for the allowance/charge
|
||||||
* @return the percentage
|
* @return the percentage
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
public interface IZUGFeRDCashDiscount {
|
||||||
|
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @return this particular cash discount as cross industry invoice XML
|
||||||
|
*/
|
||||||
|
public String getAsCII();
|
||||||
|
|
||||||
|
/***
|
||||||
|
* since EN16931 voted not to have (or even allow) cash discounts in their core invoice the german
|
||||||
|
* XRechnung CIUS defined it's own proprietary format for a freetext field
|
||||||
|
* @return this particular cash discount in proprietary xrechnung format
|
||||||
|
*/
|
||||||
|
public String getAsXRechnung();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -26,12 +26,13 @@ package org.mustangproject.ZUGFeRD;
|
|||||||
* @author jstaerk
|
* @author jstaerk
|
||||||
* */
|
* */
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
|
||||||
import org.mustangproject.Item;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.mustangproject.Item;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
|
|
||||||
@JsonDeserialize(as = Item.class)
|
@JsonDeserialize(as = Item.class)
|
||||||
public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
|
public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
|
||||||
IZUGFeRDExportableProduct getProduct();
|
IZUGFeRDExportableProduct getProduct();
|
||||||
@@ -91,12 +92,22 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
|
|||||||
|
|
||||||
/***
|
/***
|
||||||
* the ID of an additionally referenced document for this item
|
* the ID of an additionally referenced document for this item
|
||||||
|
* @deprecated use {@link #getAdditionalReferences()} instead.
|
||||||
* @return the id as string
|
* @return the id as string
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
default String getAdditionalReferencedDocumentID() {
|
default String getAdditionalReferencedDocumentID() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* allows to specify multiple references (billing information)
|
||||||
|
* @return the referenced documents
|
||||||
|
*/
|
||||||
|
default IReferencedDocument[] getAdditionalReferences() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* allows to specify multiple(!) referenced documents along with e.g. their typecodes
|
* allows to specify multiple(!) referenced documents along with e.g. their typecodes
|
||||||
@@ -140,6 +151,6 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
|
|||||||
*/
|
*/
|
||||||
default IZUGFeRDAllowanceCharge[] getItemTotalAllowances() {
|
default IZUGFeRDAllowanceCharge[] getItemTotalAllowances() {
|
||||||
return null;
|
return null;
|
||||||
};
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
|
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
|
||||||
|
|
||||||
@@ -156,4 +157,19 @@ public interface IZUGFeRDExportableProduct {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default String getCountryOfOrigin() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
default HashMap<String, String> getAttributes() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detailed information about the product
|
||||||
|
*
|
||||||
|
* @return an array containing the product classifications or {@code null} if not set
|
||||||
|
*/
|
||||||
|
default IDesignatedProductClassification[] getClassifications() { return null; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import org.mustangproject.TradeParty;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mustangproject's ZUGFeRD implementation neccessary interface for ZUGFeRD exporter Licensed under the APLv2
|
* Mustangproject's ZUGFeRD implementation neccessary interface for ZUGFeRD exporter Licensed under the APLv2
|
||||||
*
|
*
|
||||||
@@ -114,12 +112,17 @@ public interface IZUGFeRDExportableTradeParty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First and last name of the recipient
|
* e.g. first and last name of the owner
|
||||||
*
|
*
|
||||||
* @return First and last name of the recipient
|
* @return full name of the party
|
||||||
*/
|
*/
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return description, e.g. if it's a small company
|
||||||
|
*/
|
||||||
|
default String getDescription() { return null; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Postal code of the recipient
|
* Postal code of the recipient
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -18,11 +18,13 @@
|
|||||||
*********************************************************************** */
|
*********************************************************************** */
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import jakarta.activation.DataSource;
|
||||||
|
import org.mustangproject.FileAttachment;
|
||||||
|
|
||||||
public interface IZUGFeRDExporter extends Closeable, IExporter {
|
public interface IZUGFeRDExporter extends Closeable, IExporter {
|
||||||
/**
|
/**
|
||||||
* factory: loads a PDF file and returns an appropriate exporter
|
* factory: loads a PDF file and returns an appropriate exporter
|
||||||
@@ -63,6 +65,8 @@ public interface IZUGFeRDExporter extends Closeable, IExporter {
|
|||||||
public String getNamespaceForVersion(int ver);
|
public String getNamespaceForVersion(int ver);
|
||||||
public String getPrefixForVersion(int ver) ;
|
public String getPrefixForVersion(int ver) ;
|
||||||
public IZUGFeRDExporter disableAutoClose(boolean disableAutoClose);
|
public IZUGFeRDExporter disableAutoClose(boolean disableAutoClose);
|
||||||
|
public void attachFile(FileAttachment file);
|
||||||
|
public void attachFile(String filename, byte[] data, String mimetype, String relation);
|
||||||
public IXMLProvider getProvider();
|
public IXMLProvider getProvider();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,22 +18,19 @@
|
|||||||
*********************************************************************** */
|
*********************************************************************** */
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
import org.mustangproject.SchemedID;
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
public interface IZUGFeRDLegalOrganisation {
|
public interface IZUGFeRDLegalOrganisation {
|
||||||
|
|
||||||
/***
|
|
||||||
*
|
|
||||||
* @return the ID of the legal organisation
|
|
||||||
*/
|
|
||||||
public String getID();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return the scheme attribute of the legal organization=the type of the identification, e.g. 0002=Siren
|
* @return the scheme attribute of the legal organization=the type of the identification, e.g. 0002=Siren, and its value
|
||||||
*/
|
*/
|
||||||
public String getSchemeID();
|
public SchemedID getSchemedID();
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* @return the TradingBusinessName of the legal organisation
|
||||||
|
*/
|
||||||
|
public String getTradingBusinessName();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,15 @@
|
|||||||
*********************************************************************** */
|
*********************************************************************** */
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
|
||||||
public interface IZUGFeRDTradeSettlement {
|
public interface IZUGFeRDTradeSettlement {
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* gets the applicableHeaderTradeSettlement
|
* gets the applicableHeaderTradeSettlement
|
||||||
* @return zf2 xml
|
* @return zf2 xml
|
||||||
*/
|
*/
|
||||||
|
@JsonIgnore
|
||||||
String getSettlementXML();
|
String getSettlementXML();
|
||||||
|
|
||||||
|
|
||||||
@@ -31,6 +34,7 @@ public interface IZUGFeRDTradeSettlement {
|
|||||||
* gets the applicableHeaderTradePayment
|
* gets the applicableHeaderTradePayment
|
||||||
* @return zf2 xml
|
* @return zf2 xml
|
||||||
*/
|
*/
|
||||||
|
@JsonIgnore
|
||||||
default String getPaymentXML() {
|
default String getPaymentXML() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,35 +22,30 @@ import org.mustangproject.XMLTools;
|
|||||||
|
|
||||||
public interface IZUGFeRDTradeSettlementDebit extends IZUGFeRDTradeSettlement {
|
public interface IZUGFeRDTradeSettlementDebit extends IZUGFeRDTradeSettlement {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default String getSettlementXML() {
|
default String getSettlementXML() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String xml = "<ram:SpecifiedTradeSettlementPaymentMeans>"
|
String xml = "<ram:SpecifiedTradeSettlementPaymentMeans>"
|
||||||
+ "<ram:TypeCode>59</ram:TypeCode>"
|
+ "<ram:TypeCode>59</ram:TypeCode>"
|
||||||
|
+ "<ram:Information>SEPA direct debit</ram:Information>"
|
||||||
+ "<ram:PayerPartyDebtorFinancialAccount>"
|
+ "<ram:PayerPartyDebtorFinancialAccount>"
|
||||||
+ "<ram:IBANID>"+XMLTools.encodeXML(getIBAN())+"</ram:IBANID>"
|
+ "<ram:IBANID>" + XMLTools.encodeXML(getIBAN()) + "</ram:IBANID>"
|
||||||
+ "</ram:PayerPartyDebtorFinancialAccount>";
|
+ "</ram:PayerPartyDebtorFinancialAccount>";
|
||||||
|
|
||||||
xml += "</ram:SpecifiedTradeSettlementPaymentMeans>";
|
xml += "</ram:SpecifiedTradeSettlementPaymentMeans>";
|
||||||
return xml;
|
return xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default String getPaymentXML() {
|
default String getPaymentXML() {
|
||||||
return "<ram:DirectDebitMandateID>"+XMLTools.encodeXML(getMandate())+"</ram:DirectDebitMandateID>";
|
return "<ram:DirectDebitMandateID>" + XMLTools.encodeXML(getMandate()) + "</ram:DirectDebitMandateID>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @return IBAN of the debtor (optional)
|
* @return IBAN of the debtor (optional)
|
||||||
*/
|
*/
|
||||||
String getIBAN();
|
String getIBAN();
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @return sepa direct debit mandate reference
|
* @return sepa direct debit mandate reference
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
*********************************************************************** */
|
*********************************************************************** */
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import org.mustangproject.XMLTools;
|
import org.mustangproject.XMLTools;
|
||||||
|
|
||||||
public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement {
|
public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement {
|
||||||
@@ -27,6 +28,7 @@ public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement
|
|||||||
*
|
*
|
||||||
* @return payment information text
|
* @return payment information text
|
||||||
*/
|
*/
|
||||||
|
@JsonIgnore
|
||||||
default String getOwnPaymentInfoText() {
|
default String getOwnPaymentInfoText() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -59,6 +61,7 @@ public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
default String getSettlementXML() {
|
default String getSettlementXML() {
|
||||||
String accountNameStr="";
|
String accountNameStr="";
|
||||||
if (getAccountName()!=null) {
|
if (getAccountName()!=null) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* the linecalculator does the math within an item line, and e.g. calculates quantity*price.
|
* the linecalculator does the math within an item line, and e.g. calculates quantity*price.
|
||||||
@@ -33,14 +34,18 @@ public class LineCalculator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal vatPercent = currentItem.getProduct().getVATPercent();
|
BigDecimal vatPercent = null;
|
||||||
if (vatPercent == null)
|
if (currentItem.getProduct()!=null) {
|
||||||
|
vatPercent = currentItem.getProduct().getVATPercent();
|
||||||
|
}
|
||||||
|
if (vatPercent == null) {
|
||||||
vatPercent = BigDecimal.ZERO;
|
vatPercent = BigDecimal.ZERO;
|
||||||
|
}
|
||||||
BigDecimal multiplicator = vatPercent.divide(BigDecimal.valueOf(100));
|
BigDecimal multiplicator = vatPercent.divide(BigDecimal.valueOf(100));
|
||||||
priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159
|
priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159
|
||||||
price = priceGross.subtract(allowance).add(charge);
|
price = priceGross.subtract(allowance).add(charge);
|
||||||
itemTotalNetAmount = currentItem.getQuantity().multiply(getPrice()).divide(currentItem.getBasisQuantity())
|
itemTotalNetAmount = currentItem.getQuantity().multiply(getPrice()).divide(currentItem.getBasisQuantity(), 18, RoundingMode.HALF_UP)
|
||||||
.subtract(allowanceItemTotal).setScale(2, BigDecimal.ROUND_HALF_UP);
|
.subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
|
||||||
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);
|
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,31 +19,35 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
|
||||||
import org.apache.pdfbox.preflight.PreflightDocument;
|
|
||||||
import org.apache.pdfbox.preflight.exception.ValidationException;
|
|
||||||
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
public class OXExporterFromA1 extends OXExporterFromA3 implements IZUGFeRDExporter {
|
import org.apache.pdfbox.preflight.PreflightDocument;
|
||||||
|
import org.apache.pdfbox.preflight.ValidationResult;
|
||||||
|
import org.apache.pdfbox.preflight.exception.ValidationException;
|
||||||
|
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
||||||
|
|
||||||
|
import jakarta.activation.DataSource;
|
||||||
|
|
||||||
|
public class OXExporterFromA1 extends OXExporterFromA3 {
|
||||||
protected boolean ignorePDFAErrors = false;
|
protected boolean ignorePDFAErrors = false;
|
||||||
|
|
||||||
public OXExporterFromA1 ignorePDFAErrors() {
|
@Override
|
||||||
|
public OXExporterFromA1 ignorePDFAErrors() {
|
||||||
this.ignorePDFAErrors = true;
|
this.ignorePDFAErrors = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isValidA1(DataSource dataSource) throws IOException {
|
private static boolean isValidA1(DataSource dataSource) throws IOException {
|
||||||
return getPDFAParserValidationResult(new PreflightParser(dataSource));
|
return getPDFAParserValidationResult(PreflightParserHelper.createPreflightParser(dataSource));
|
||||||
}
|
}
|
||||||
/***
|
/***
|
||||||
* internal helper function: get namespace for order-x
|
* internal helper function: get namespace for order-x
|
||||||
* @param ver the order-x version
|
* @param ver the order-x version
|
||||||
* @return the URN of the namespace
|
* @return the URN of the namespace
|
||||||
*/
|
*/
|
||||||
public String getNamespaceForVersion(int ver) {
|
@Override
|
||||||
|
public String getNamespaceForVersion(int ver) {
|
||||||
return "urn:factur-x:pdfa:CrossIndustryDocument:1p0#";
|
return "urn:factur-x:pdfa:CrossIndustryDocument:1p0#";
|
||||||
}
|
}
|
||||||
/***
|
/***
|
||||||
@@ -51,7 +55,8 @@ public class OXExporterFromA1 extends OXExporterFromA3 implements IZUGFeRDExport
|
|||||||
* @param ver the ox version
|
* @param ver the ox version
|
||||||
* @return the namespace prefix as string, without colon
|
* @return the namespace prefix as string, without colon
|
||||||
*/
|
*/
|
||||||
public String getPrefixForVersion(int ver) {
|
@Override
|
||||||
|
public String getPrefixForVersion(int ver) {
|
||||||
return "fx";
|
return "fx";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,19 +66,19 @@ public class OXExporterFromA1 extends OXExporterFromA3 implements IZUGFeRDExport
|
|||||||
* NonSequentialParser. Some additional controls are present to check a set of
|
* NonSequentialParser. Some additional controls are present to check a set of
|
||||||
* PDF/A requirements. (Stream length consistency, EOL after some Keyword...)
|
* PDF/A requirements. (Stream length consistency, EOL after some Keyword...)
|
||||||
*/
|
*/
|
||||||
parser.parse();// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
|
// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
|
||||||
|
|
||||||
try (PreflightDocument document = parser.getPreflightDocument()) {
|
try (PreflightDocument document = (PreflightDocument) parser.parse()) {
|
||||||
/*
|
/*
|
||||||
* Once the syntax validation is done, the parser can provide a
|
* Once the syntax validation is done, the parser can provide a
|
||||||
* PreflightDocument (that inherits from PDDocument) This document process the
|
* PreflightDocument (that inherits from PDDocument) This document process the
|
||||||
* end of PDF/A validation.
|
* end of PDF/A validation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
document.validate();
|
ValidationResult res = document.validate();
|
||||||
|
|
||||||
// Get validation result
|
// Get validation result
|
||||||
return document.getResult().isValid();
|
return res.isValid();
|
||||||
} catch (ValidationException e) {
|
} catch (ValidationException e) {
|
||||||
/*
|
/*
|
||||||
* the parse method can throw a SyntaxValidationException if the PDF file can't
|
* the parse method can throw a SyntaxValidationException if the PDF file can't
|
||||||
@@ -85,14 +90,17 @@ public class OXExporterFromA1 extends OXExporterFromA3 implements IZUGFeRDExport
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public OXExporterFromA1 setProfile(Profile p) {
|
@Override
|
||||||
|
public OXExporterFromA1 setProfile(Profile p) {
|
||||||
return (OXExporterFromA1)super.setProfile(p);
|
return (OXExporterFromA1)super.setProfile(p);
|
||||||
}
|
}
|
||||||
public OXExporterFromA1 setProfile(String profileName) {
|
@Override
|
||||||
|
public OXExporterFromA1 setProfile(String profileName) {
|
||||||
return (OXExporterFromA1)super.setProfile(profileName);
|
return (OXExporterFromA1)super.setProfile(profileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
|
@Override
|
||||||
|
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
|
||||||
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
|
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
|
||||||
throw new IOException("File is not a valid PDF/A input file");
|
throw new IOException("File is not a valid PDF/A input file");
|
||||||
}
|
}
|
||||||
@@ -104,32 +112,41 @@ public class OXExporterFromA1 extends OXExporterFromA3 implements IZUGFeRDExport
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OXExporterFromA1 load(String pdfFilename) throws IOException {
|
@Override
|
||||||
|
public OXExporterFromA1 load(String pdfFilename) throws IOException {
|
||||||
return (OXExporterFromA1) super.load(pdfFilename);
|
return (OXExporterFromA1) super.load(pdfFilename);
|
||||||
}
|
}
|
||||||
public OXExporterFromA1 load(byte[] pdfBinary) throws IOException {
|
@Override
|
||||||
|
public OXExporterFromA1 load(byte[] pdfBinary) throws IOException {
|
||||||
return (OXExporterFromA1) super.load(pdfBinary);
|
return (OXExporterFromA1) super.load(pdfBinary);
|
||||||
}
|
}
|
||||||
public OXExporterFromA1 load(InputStream pdfSource) throws IOException{
|
@Override
|
||||||
|
public OXExporterFromA1 load(InputStream pdfSource) throws IOException{
|
||||||
return (OXExporterFromA1) super.load(pdfSource);
|
return (OXExporterFromA1) super.load(pdfSource);
|
||||||
}
|
}
|
||||||
public OXExporterFromA1 setCreator(String creator) {
|
@Override
|
||||||
|
public OXExporterFromA1 setCreator(String creator) {
|
||||||
return (OXExporterFromA1) super.setCreator(creator);
|
return (OXExporterFromA1) super.setCreator(creator);
|
||||||
}
|
}
|
||||||
public OXExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
@Override
|
||||||
|
public OXExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
||||||
return (OXExporterFromA1) super.setConformanceLevel(newLevel);
|
return (OXExporterFromA1) super.setConformanceLevel(newLevel);
|
||||||
}
|
}
|
||||||
public OXExporterFromA1 setProducer(String producer){
|
@Override
|
||||||
|
public OXExporterFromA1 setProducer(String producer){
|
||||||
return (OXExporterFromA1) super.setProducer(producer);
|
return (OXExporterFromA1) super.setProducer(producer);
|
||||||
}
|
}
|
||||||
public OXExporterFromA1 setZUGFeRDVersion(int version){
|
@Override
|
||||||
|
public OXExporterFromA1 setZUGFeRDVersion(int version){
|
||||||
return (OXExporterFromA1) super.setZUGFeRDVersion(version);
|
return (OXExporterFromA1) super.setZUGFeRDVersion(version);
|
||||||
}
|
}
|
||||||
public OXExporterFromA1 setXML(byte[] zugferdData) throws IOException{
|
@Override
|
||||||
|
public OXExporterFromA1 setXML(byte[] zugferdData) throws IOException{
|
||||||
return (OXExporterFromA1) super.setXML(zugferdData);
|
return (OXExporterFromA1) super.setXML(zugferdData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OXExporterFromA1 disableAutoClose(boolean disableAutoClose){
|
@Override
|
||||||
|
public OXExporterFromA1 disableAutoClose(boolean disableAutoClose){
|
||||||
return (OXExporterFromA1) super.disableAutoClose(disableAutoClose);
|
return (OXExporterFromA1) super.disableAutoClose(disableAutoClose);
|
||||||
}
|
}
|
||||||
public OXExporterFromA1 convertOnly() {
|
public OXExporterFromA1 convertOnly() {
|
||||||
|
|||||||
@@ -20,20 +20,38 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import org.apache.pdfbox.cos.*;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
|
import org.apache.pdfbox.cos.COSArray;
|
||||||
|
import org.apache.pdfbox.cos.COSBase;
|
||||||
|
import org.apache.pdfbox.cos.COSDictionary;
|
||||||
|
import org.apache.pdfbox.cos.COSName;
|
||||||
|
import org.apache.pdfbox.cos.COSObject;
|
||||||
import org.apache.pdfbox.io.IOUtils;
|
import org.apache.pdfbox.io.IOUtils;
|
||||||
import org.apache.pdfbox.pdmodel.*;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
||||||
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo;
|
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo;
|
||||||
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
|
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
|
||||||
import org.apache.pdfbox.pdmodel.font.PDCIDFontType2;
|
|
||||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
|
||||||
import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
|
|
||||||
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
|
||||||
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
|
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
|
||||||
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
|
|
||||||
import org.apache.xmpbox.XMPMetadata;
|
import org.apache.xmpbox.XMPMetadata;
|
||||||
import org.apache.xmpbox.schema.AdobePDFSchema;
|
import org.apache.xmpbox.schema.AdobePDFSchema;
|
||||||
import org.apache.xmpbox.schema.DublinCoreSchema;
|
import org.apache.xmpbox.schema.DublinCoreSchema;
|
||||||
@@ -47,16 +65,13 @@ import org.apache.xmpbox.xml.XmpSerializer;
|
|||||||
import org.mustangproject.EStandard;
|
import org.mustangproject.EStandard;
|
||||||
import org.mustangproject.FileAttachment;
|
import org.mustangproject.FileAttachment;
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
import jakarta.activation.DataSource;
|
||||||
import javax.activation.FileDataSource;
|
import jakarta.activation.FileDataSource;
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
||||||
|
|
||||||
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
||||||
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<FileAttachment>();
|
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This flag controls whether or not the metadata is overwritten, or kind of merged.
|
* This flag controls whether or not the metadata is overwritten, or kind of merged.
|
||||||
@@ -112,9 +127,6 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
protected String orderXDocumentType = "ORDER";
|
protected String orderXDocumentType = "ORDER";
|
||||||
|
|
||||||
|
|
||||||
private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
|
|
||||||
|
|
||||||
|
|
||||||
private boolean attachZUGFeRDHeaders = true;
|
private boolean attachZUGFeRDHeaders = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,7 +135,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
*
|
*
|
||||||
* @param pdfFilename filename of an PDF/A1 compliant document
|
* @param pdfFilename filename of an PDF/A1 compliant document
|
||||||
*/
|
*/
|
||||||
public OXExporterFromA3 load(String pdfFilename) throws IOException {
|
@Override
|
||||||
|
public OXExporterFromA3 load(String pdfFilename) throws IOException {
|
||||||
|
|
||||||
ensurePDFIsValid(new FileDataSource(pdfFilename));
|
ensurePDFIsValid(new FileDataSource(pdfFilename));
|
||||||
try (FileInputStream pdf = new FileInputStream(pdfFilename)) {
|
try (FileInputStream pdf = new FileInputStream(pdfFilename)) {
|
||||||
@@ -131,11 +144,13 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IXMLProvider getProvider() {
|
@Override
|
||||||
|
public IXMLProvider getProvider() {
|
||||||
return xmlProvider;
|
return xmlProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OXExporterFromA3 setProfile(Profile p) {
|
@Override
|
||||||
|
public OXExporterFromA3 setProfile(Profile p) {
|
||||||
this.profile = p;
|
this.profile = p;
|
||||||
if (xmlProvider != null) {
|
if (xmlProvider != null) {
|
||||||
xmlProvider.setProfile(p);
|
xmlProvider.setProfile(p);
|
||||||
@@ -143,7 +158,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OXExporterFromA3 setProfile(String profilename) {
|
@Override
|
||||||
|
public OXExporterFromA3 setProfile(String profilename) {
|
||||||
this.profile = Profiles.getByName(profilename);
|
this.profile = Profiles.getByName(profilename);
|
||||||
|
|
||||||
if (xmlProvider != null) {
|
if (xmlProvider != null) {
|
||||||
@@ -152,7 +168,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OXExporterFromA3 addAdditionalFile(String name, byte[] content) {
|
@Override
|
||||||
|
public OXExporterFromA3 addAdditionalFile(String name, byte[] content) {
|
||||||
fileAttachments.add(new FileAttachment(name, "text/xml", "Supplement", content).setDescription("ZUGFeRD extension/additional data"));
|
fileAttachments.add(new FileAttachment(name, "text/xml", "Supplement", content).setDescription("ZUGFeRD extension/additional data"));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -165,9 +182,10 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
*
|
*
|
||||||
* @param pdfBinary binary of a PDF/A1 compliant document
|
* @param pdfBinary binary of a PDF/A1 compliant document
|
||||||
*/
|
*/
|
||||||
public OXExporterFromA3 load(byte[] pdfBinary) throws IOException {
|
@Override
|
||||||
|
public OXExporterFromA3 load(byte[] pdfBinary) throws IOException {
|
||||||
ensurePDFIsValid(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
|
ensurePDFIsValid(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
|
||||||
doc = PDDocument.load(pdfBinary);
|
doc = Loader.loadPDF(pdfBinary);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,11 +193,13 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void attachFile(FileAttachment file) {
|
@Override
|
||||||
|
public void attachFile(FileAttachment file) {
|
||||||
fileAttachments.add(file);
|
fileAttachments.add(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void attachFile(String filename, byte[] data, String mimetype, String relation) {
|
@Override
|
||||||
|
public void attachFile(String filename, byte[] data, String mimetype, String relation) {
|
||||||
FileAttachment fa = new FileAttachment(filename, mimetype, relation, data);
|
FileAttachment fa = new FileAttachment(filename, mimetype, relation, data);
|
||||||
fileAttachments.add(fa);
|
fileAttachments.add(fa);
|
||||||
}
|
}
|
||||||
@@ -189,7 +209,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* @param ZUGFeRDfilename the pdf file name
|
* @param ZUGFeRDfilename the pdf file name
|
||||||
* @throws IOException if anything is wrong in the target location
|
* @throws IOException if anything is wrong in the target location
|
||||||
*/
|
*/
|
||||||
public void export(String ZUGFeRDfilename) throws IOException {
|
@Override
|
||||||
|
public void export(String ZUGFeRDfilename) throws IOException {
|
||||||
if (!documentPrepared) {
|
if (!documentPrepared) {
|
||||||
prepareDocument();
|
prepareDocument();
|
||||||
}
|
}
|
||||||
@@ -216,7 +237,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* @param output the OutputStream
|
* @param output the OutputStream
|
||||||
* @throws IOException if anything is wrong in the OutputStream
|
* @throws IOException if anything is wrong in the OutputStream
|
||||||
*/
|
*/
|
||||||
public void export(OutputStream output) throws IOException {
|
@Override
|
||||||
|
public void export(OutputStream output) throws IOException {
|
||||||
if (!documentPrepared) {
|
if (!documentPrepared) {
|
||||||
prepareDocument();
|
prepareDocument();
|
||||||
}
|
}
|
||||||
@@ -242,7 +264,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* @param data the binary data of the file/attachment
|
* @param data the binary data of the file/attachment
|
||||||
* @throws java.io.IOException if anything is wrong with filename
|
* @throws java.io.IOException if anything is wrong with filename
|
||||||
*/
|
*/
|
||||||
public void PDFAttachGenericFile(String filename, String relationship, String description,
|
@Override
|
||||||
|
public void PDFAttachGenericFile(String filename, String relationship, String description,
|
||||||
String subType, byte[] data) throws IOException {
|
String subType, byte[] data) throws IOException {
|
||||||
PDFAttachGenericFile(this.doc, filename, relationship, description, subType, data);
|
PDFAttachGenericFile(this.doc, filename, relationship, description, subType, data);
|
||||||
}
|
}
|
||||||
@@ -259,7 +282,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* @param data the binary data of the file/attachment
|
* @param data the binary data of the file/attachment
|
||||||
* @throws IOException if anything is wrong with filename
|
* @throws IOException if anything is wrong with filename
|
||||||
*/
|
*/
|
||||||
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
|
@Override
|
||||||
|
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
|
||||||
String subType, byte[] data) throws IOException {
|
String subType, byte[] data) throws IOException {
|
||||||
fileAttached = true;
|
fileAttached = true;
|
||||||
|
|
||||||
@@ -278,7 +302,7 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
ef.setSize(data.length);
|
ef.setSize(data.length);
|
||||||
ef.setCreationDate(new GregorianCalendar());
|
ef.setCreationDate(new GregorianCalendar());
|
||||||
|
|
||||||
ef.setModDate(GregorianCalendar.getInstance());
|
ef.setModDate(Calendar.getInstance());
|
||||||
|
|
||||||
fs.setEmbeddedFile(ef);
|
fs.setEmbeddedFile(ef);
|
||||||
|
|
||||||
@@ -310,7 +334,7 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
doc.getDocumentCatalog().setNames(names);
|
doc.getDocumentCatalog().setNames(names);
|
||||||
|
|
||||||
// AF entry (Array) in catalog with the FileSpec
|
// AF entry (Array) in catalog with the FileSpec
|
||||||
COSBase AFEntry = (COSBase) doc.getDocumentCatalog().getCOSObject().getItem("AF");
|
COSBase AFEntry = doc.getDocumentCatalog().getCOSObject().getItem("AF");
|
||||||
if ((AFEntry == null)) {
|
if ((AFEntry == null)) {
|
||||||
COSArray cosArray = new COSArray();
|
COSArray cosArray = new COSArray();
|
||||||
cosArray.add(fs);
|
cosArray.add(fs);
|
||||||
@@ -336,7 +360,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* @param zugferdData XML data to be set as a byte array (XML file in raw form).
|
* @param zugferdData XML data to be set as a byte array (XML file in raw form).
|
||||||
* @throws IOException (should not happen)
|
* @throws IOException (should not happen)
|
||||||
*/
|
*/
|
||||||
public OXExporterFromA3 setXML(byte[] zugferdData) throws IOException {
|
@Override
|
||||||
|
public OXExporterFromA3 setXML(byte[] zugferdData) throws IOException {
|
||||||
CustomXMLProvider cus = new CustomXMLProvider();
|
CustomXMLProvider cus = new CustomXMLProvider();
|
||||||
cus.setXML(zugferdData);
|
cus.setXML(zugferdData);
|
||||||
this.setXMLProvider(cus);
|
this.setXMLProvider(cus);
|
||||||
@@ -351,11 +376,13 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
*
|
*
|
||||||
* @param pdfSource source to read a PDF/A1 compliant document from
|
* @param pdfSource source to read a PDF/A1 compliant document from
|
||||||
*/
|
*/
|
||||||
public OXExporterFromA3 load(InputStream pdfSource) throws IOException {
|
@Override
|
||||||
|
public OXExporterFromA3 load(InputStream pdfSource) throws IOException {
|
||||||
return load(readAllBytes(pdfSource));
|
return load(readAllBytes(pdfSource));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
|
@Override
|
||||||
|
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,23 +405,27 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* <p>
|
* <p>
|
||||||
* Feel free to pass "A" as new level if you know what you are doing :-)
|
* Feel free to pass "A" as new level if you know what you are doing :-)
|
||||||
*/
|
*/
|
||||||
public OXExporterFromA3 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
@Override
|
||||||
|
public OXExporterFromA3 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
||||||
conformanceLevel = newLevel;
|
conformanceLevel = newLevel;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public OXExporterFromA3 setCreator(String creator) {
|
@Override
|
||||||
|
public OXExporterFromA3 setCreator(String creator) {
|
||||||
this.creator = creator;
|
this.creator = creator;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OXExporterFromA3 setCreatorTool(String creatorTool) {
|
@Override
|
||||||
|
public OXExporterFromA3 setCreatorTool(String creatorTool) {
|
||||||
this.creatorTool = creatorTool;
|
this.creatorTool = creatorTool;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OXExporterFromA3 setProducer(String producer) {
|
@Override
|
||||||
|
public OXExporterFromA3 setProducer(String producer) {
|
||||||
this.producer = producer;
|
this.producer = producer;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -413,7 +444,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OXExporterFromA3 setAttachZUGFeRDHeaders(boolean attachHeaders) {
|
@Override
|
||||||
|
protected OXExporterFromA3 setAttachZUGFeRDHeaders(boolean attachHeaders) {
|
||||||
this.attachZUGFeRDHeaders = attachHeaders;
|
this.attachZUGFeRDHeaders = attachHeaders;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -426,7 +458,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
*
|
*
|
||||||
* @param metadata the PDFbox XMPMetadata object
|
* @param metadata the PDFbox XMPMetadata object
|
||||||
*/
|
*/
|
||||||
protected void addXMP(XMPMetadata metadata) {
|
@Override
|
||||||
|
protected void addXMP(XMPMetadata metadata) {
|
||||||
|
|
||||||
if (attachZUGFeRDHeaders) {
|
if (attachZUGFeRDHeaders) {
|
||||||
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, 1, true, xmlProvider.getProfile(),
|
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, 1, true, xmlProvider.getProfile(),
|
||||||
@@ -453,12 +486,14 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
|
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
|
||||||
* @throws IOException if anything is wrong with already loaded PDF
|
* @throws IOException if anything is wrong with already loaded PDF
|
||||||
*/
|
*/
|
||||||
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
|
@Override
|
||||||
|
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
|
||||||
this.trans = trans;
|
this.trans = trans;
|
||||||
return prepare();
|
return prepare();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExporter prepare() throws IOException {
|
@Override
|
||||||
|
public IExporter prepare() throws IOException {
|
||||||
prepareDocument();
|
prepareDocument();
|
||||||
xmlProvider.generateXML(trans);
|
xmlProvider.generateXML(trans);
|
||||||
String filename = "order-x.xml";
|
String filename = "order-x.xml";
|
||||||
@@ -477,7 +512,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* Reads the XMPMetadata from the PDDocument, if it exists.
|
* Reads the XMPMetadata from the PDDocument, if it exists.
|
||||||
* Otherwise creates XMPMetadata.
|
* Otherwise creates XMPMetadata.
|
||||||
*/
|
*/
|
||||||
protected XMPMetadata getXmpMetadata() throws IOException {
|
@Override
|
||||||
|
protected XMPMetadata getXmpMetadata() throws IOException {
|
||||||
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
|
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
|
||||||
if ((meta != null) && (meta.getLength() > 0)) {
|
if ((meta != null) && (meta.getLength() > 0)) {
|
||||||
try {
|
try {
|
||||||
@@ -490,7 +526,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return XMPMetadata.createXMPMetadata();
|
return XMPMetadata.createXMPMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
|
@Override
|
||||||
|
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
new XmpSerializer().serialize(xmpMetadata, buffer, true); // see https://github.com/ZUGFeRD/mustangproject/issues/44
|
new XmpSerializer().serialize(xmpMetadata, buffer, true); // see https://github.com/ZUGFeRD/mustangproject/issues/44
|
||||||
return buffer.toByteArray();
|
return buffer.toByteArray();
|
||||||
@@ -500,7 +537,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* Sets the producer if the overwrite flag is set or the producer is not already set.
|
* Sets the producer if the overwrite flag is set or the producer is not already set.
|
||||||
* Sets the PDFVersion to 1.4 if the field is empty.
|
* Sets the PDFVersion to 1.4 if the field is empty.
|
||||||
*/
|
*/
|
||||||
protected void writeAdobePDFSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected void writeAdobePDFSchema(XMPMetadata xmp) {
|
||||||
AdobePDFSchema pdf = getAdobePDFSchema(xmp);
|
AdobePDFSchema pdf = getAdobePDFSchema(xmp);
|
||||||
if (overwrite || isEmpty(pdf.getProducer()))
|
if (overwrite || isEmpty(pdf.getProducer()))
|
||||||
pdf.setProducer(producer);
|
pdf.setProducer(producer);
|
||||||
@@ -510,7 +548,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
* Returns the AdobePDFSchema from the XMPMetadata if it exists.
|
* Returns the AdobePDFSchema from the XMPMetadata if it exists.
|
||||||
* If the overwrite flag is set or no AdobePDFSchema exists in the XMPMetadata, it is created, added and returned.
|
* If the overwrite flag is set or no AdobePDFSchema exists in the XMPMetadata, it is created, added and returned.
|
||||||
*/
|
*/
|
||||||
protected AdobePDFSchema getAdobePDFSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected AdobePDFSchema getAdobePDFSchema(XMPMetadata xmp) {
|
||||||
AdobePDFSchema pdf = xmp.getAdobePDFSchema();
|
AdobePDFSchema pdf = xmp.getAdobePDFSchema();
|
||||||
if (pdf != null)
|
if (pdf != null)
|
||||||
if (overwrite)
|
if (overwrite)
|
||||||
@@ -520,7 +559,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return xmp.createAndAddAdobePDFSchema();
|
return xmp.createAndAddAdobePDFSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writePDFAIdentificationSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected void writePDFAIdentificationSchema(XMPMetadata xmp) {
|
||||||
PDFAIdentificationSchema pdfaid = getPDFAIdentificationSchema(xmp);
|
PDFAIdentificationSchema pdfaid = getPDFAIdentificationSchema(xmp);
|
||||||
if (overwrite || isEmpty(pdfaid.getConformance())) {
|
if (overwrite || isEmpty(pdfaid.getConformance())) {
|
||||||
try {
|
try {
|
||||||
@@ -535,17 +575,19 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
pdfaid.setPart(3);
|
pdfaid.setPart(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PDFAIdentificationSchema getPDFAIdentificationSchema(XMPMetadata xmp) {
|
@Override
|
||||||
PDFAIdentificationSchema pdfaid = xmp.getPDFIdentificationSchema();
|
protected PDFAIdentificationSchema getPDFAIdentificationSchema(XMPMetadata xmp) {
|
||||||
|
PDFAIdentificationSchema pdfaid = xmp.getPDFAIdentificationSchema();
|
||||||
if (pdfaid != null)
|
if (pdfaid != null)
|
||||||
if (overwrite)
|
if (overwrite)
|
||||||
xmp.removeSchema(pdfaid);
|
xmp.removeSchema(pdfaid);
|
||||||
else
|
else
|
||||||
return pdfaid;
|
return pdfaid;
|
||||||
return xmp.createAndAddPFAIdentificationSchema();
|
return xmp.createAndAddPDFAIdentificationSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeDublinCoreSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected void writeDublinCoreSchema(XMPMetadata xmp) {
|
||||||
DublinCoreSchema dc = getDublinCoreSchema(xmp);
|
DublinCoreSchema dc = getDublinCoreSchema(xmp);
|
||||||
if (dc.getFormat() == null)
|
if (dc.getFormat() == null)
|
||||||
dc.setFormat("application/pdf");
|
dc.setFormat("application/pdf");
|
||||||
@@ -568,7 +610,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DublinCoreSchema getDublinCoreSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected DublinCoreSchema getDublinCoreSchema(XMPMetadata xmp) {
|
||||||
DublinCoreSchema dc = xmp.getDublinCoreSchema();
|
DublinCoreSchema dc = xmp.getDublinCoreSchema();
|
||||||
if (dc != null)
|
if (dc != null)
|
||||||
if (overwrite)
|
if (overwrite)
|
||||||
@@ -578,15 +621,17 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return xmp.createAndAddDublinCoreSchema();
|
return xmp.createAndAddDublinCoreSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeXMLBasicSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected void writeXMLBasicSchema(XMPMetadata xmp) {
|
||||||
XMPBasicSchema xsb = getXmpBasicSchema(xmp);
|
XMPBasicSchema xsb = getXmpBasicSchema(xmp);
|
||||||
if (overwrite || isEmpty(xsb.getCreatorTool()) || "UnknownApplication".equals(xsb.getCreatorTool()))
|
if (overwrite || isEmpty(xsb.getCreatorTool()) || "UnknownApplication".equals(xsb.getCreatorTool()))
|
||||||
xsb.setCreatorTool(creatorTool);
|
xsb.setCreatorTool(creatorTool);
|
||||||
if (overwrite || xsb.getCreateDate() == null)
|
if (overwrite || xsb.getCreateDate() == null)
|
||||||
xsb.setCreateDate(GregorianCalendar.getInstance());
|
xsb.setCreateDate(Calendar.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected XMPBasicSchema getXmpBasicSchema(XMPMetadata xmp) {
|
@Override
|
||||||
|
protected XMPBasicSchema getXmpBasicSchema(XMPMetadata xmp) {
|
||||||
XMPBasicSchema xsb = xmp.getXMPBasicSchema();
|
XMPBasicSchema xsb = xmp.getXMPBasicSchema();
|
||||||
if (xsb != null)
|
if (xsb != null)
|
||||||
if (overwrite)
|
if (overwrite)
|
||||||
@@ -596,7 +641,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return xmp.createAndAddXMPBasicSchema();
|
return xmp.createAndAddXMPBasicSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeDocumentInformation() {
|
@Override
|
||||||
|
protected void writeDocumentInformation() {
|
||||||
String fullProducer = producer + " (via mustangproject.org " + Version.VERSION + ")";
|
String fullProducer = producer + " (via mustangproject.org " + Version.VERSION + ")";
|
||||||
PDDocumentInformation info = doc.getDocumentInformation();
|
PDDocumentInformation info = doc.getDocumentInformation();
|
||||||
if (overwrite || info.getCreationDate() == null)
|
if (overwrite || info.getCreationDate() == null)
|
||||||
@@ -618,7 +664,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
/**
|
/**
|
||||||
* Adds an OutputIntent and the sRGB color profile if no OutputIntent exist
|
* Adds an OutputIntent and the sRGB color profile if no OutputIntent exist
|
||||||
*/
|
*/
|
||||||
protected void addSRGBOutputIntend() throws IOException {
|
@Override
|
||||||
|
protected void addSRGBOutputIntend() throws IOException {
|
||||||
if (!doc.getDocumentCatalog().getOutputIntents().isEmpty()) {
|
if (!doc.getDocumentCatalog().getOutputIntents().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -641,7 +688,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
/**
|
/**
|
||||||
* Adds a MarkInfo element to the PDF if it doesn't already exist and sets it as marked.
|
* Adds a MarkInfo element to the PDF if it doesn't already exist and sets it as marked.
|
||||||
*/
|
*/
|
||||||
protected void setMarked() {
|
@Override
|
||||||
|
protected void setMarked() {
|
||||||
PDDocumentCatalog catalog = doc.getDocumentCatalog();
|
PDDocumentCatalog catalog = doc.getDocumentCatalog();
|
||||||
if (catalog.getMarkInfo() == null) {
|
if (catalog.getMarkInfo() == null) {
|
||||||
catalog.setMarkInfo(new PDMarkInfo(doc.getPages().getCOSObject()));
|
catalog.setMarkInfo(new PDMarkInfo(doc.getPages().getCOSObject()));
|
||||||
@@ -652,7 +700,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
/**
|
/**
|
||||||
* Adds a StructureTreeRoot element to the PDF if it doesn't already exist.
|
* Adds a StructureTreeRoot element to the PDF if it doesn't already exist.
|
||||||
*/
|
*/
|
||||||
protected void addStructureTreeRoot() {
|
@Override
|
||||||
|
protected void addStructureTreeRoot() {
|
||||||
if (doc.getDocumentCatalog().getStructureTreeRoot() == null) {
|
if (doc.getDocumentCatalog().getStructureTreeRoot() == null) {
|
||||||
doc.getDocumentCatalog().setStructureTreeRoot(new PDStructureTreeRoot());
|
doc.getDocumentCatalog().setStructureTreeRoot(new PDStructureTreeRoot());
|
||||||
}
|
}
|
||||||
@@ -662,19 +711,22 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
/**
|
/**
|
||||||
* @return if pdf file will be automatically closed after adding ZF
|
* @return if pdf file will be automatically closed after adding ZF
|
||||||
*/
|
*/
|
||||||
public boolean isAutoCloseDisabled() {
|
@Override
|
||||||
|
public boolean isAutoCloseDisabled() {
|
||||||
return disableAutoClose;
|
return disableAutoClose;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param disableAutoClose prevent PDF file from being closed after adding ZF
|
* @param disableAutoClose prevent PDF file from being closed after adding ZF
|
||||||
*/
|
*/
|
||||||
public OXExporterFromA3 disableAutoClose(boolean disableAutoClose) {
|
@Override
|
||||||
|
public OXExporterFromA3 disableAutoClose(boolean disableAutoClose) {
|
||||||
this.disableAutoClose = disableAutoClose;
|
this.disableAutoClose = disableAutoClose;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setXMLProvider(IXMLProvider p) {
|
@Override
|
||||||
|
protected void setXMLProvider(IXMLProvider p) {
|
||||||
this.xmlProvider = p;
|
this.xmlProvider = p;
|
||||||
if (profile != null) {
|
if (profile != null) {
|
||||||
xmlProvider.setProfile(profile);
|
xmlProvider.setProfile(profile);
|
||||||
|
|||||||
@@ -22,26 +22,19 @@ package org.mustangproject.ZUGFeRD;
|
|||||||
|
|
||||||
import static org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat.DATE;
|
import static org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat.DATE;
|
||||||
import static org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants.CORRECTEDINVOICE;
|
import static org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants.CORRECTEDINVOICE;
|
||||||
import static org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants.CATEGORY_CODES_WITH_EXEMPTION_REASON;
|
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.mustangproject.EStandard;
|
import org.mustangproject.EStandard;
|
||||||
import org.mustangproject.FileAttachment;
|
import org.mustangproject.FileAttachment;
|
||||||
import org.mustangproject.IncludedNote;
|
|
||||||
import org.mustangproject.XMLTools;
|
import org.mustangproject.XMLTools;
|
||||||
|
|
||||||
public class OXPullProvider extends ZUGFeRD2PullProvider implements IXMLProvider {
|
public class OXPullProvider extends ZUGFeRD2PullProvider {
|
||||||
|
|
||||||
protected IExportableTransaction trans;
|
protected IExportableTransaction trans;
|
||||||
protected TransactionCalculator calc;
|
protected TransactionCalculator calc;
|
||||||
@@ -333,17 +326,19 @@ public class OXPullProvider extends ZUGFeRD2PullProvider implements IXMLProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((trans.getDocumentCode() == CORRECTEDINVOICE)/*||(trans.getDocumentCode() == DocumentCodeTypeConstants.CREDITNOTE)*/) {
|
if (trans.getDocumentCode() != null) {
|
||||||
hasDueDate = false;
|
if ((trans.getDocumentCode().equals(CORRECTEDINVOICE))/*||(trans.getDocumentCode().equals (DocumentCodeTypeConstants.CREDITNOTE))*/) {
|
||||||
|
hasDueDate = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<BigDecimal, VATAmount> VATPercentAmountMap = calc.getVATPercentAmountMap();
|
final Map<BigDecimal, VATAmount> VATPercentAmountMap = calc.getVATPercentAmountMap();
|
||||||
for (final BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
|
for (final BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
|
||||||
final VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
|
final VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
|
||||||
if (amount != null) {
|
if (amount != null) {
|
||||||
final String amountCategoryCode = amount.getCategoryCode();
|
/*final String amountCategoryCode = amount.getCategoryCode();
|
||||||
final boolean displayExemptionReason = CATEGORY_CODES_WITH_EXEMPTION_REASON.contains(amountCategoryCode);
|
final boolean displayExemptionReason = CATEGORY_CODES_WITH_EXEMPTION_REASON.contains(amountCategoryCode);
|
||||||
/* xml += "<ram:ApplicableTradeTax>\n"
|
xml += "<ram:ApplicableTradeTax>\n"
|
||||||
+ "<ram:CalculatedAmount>" + currencyFormat(amount.getCalculated())
|
+ "<ram:CalculatedAmount>" + currencyFormat(amount.getCalculated())
|
||||||
+ "</ram:CalculatedAmount>\n" //currencyID=\"EUR\"
|
+ "</ram:CalculatedAmount>\n" //currencyID=\"EUR\"
|
||||||
+ "<ram:TypeCode>VAT</ram:TypeCode>\n"
|
+ "<ram:TypeCode>VAT</ram:TypeCode>\n"
|
||||||
@@ -479,13 +474,9 @@ public class OXPullProvider extends ZUGFeRD2PullProvider implements IXMLProvider
|
|||||||
+ "</rsm:SCRDMCCBDACIOMessageStructure>";
|
+ "</rsm:SCRDMCCBDACIOMessageStructure>";
|
||||||
|
|
||||||
final byte[] zugferdRaw;
|
final byte[] zugferdRaw;
|
||||||
try {
|
zugferdRaw = xml.getBytes(StandardCharsets.UTF_8);
|
||||||
zugferdRaw = xml.getBytes("UTF-8");
|
|
||||||
|
|
||||||
zugferdData = XMLTools.removeBOM(zugferdRaw);
|
zugferdData = XMLTools.removeBOM(zugferdRaw);
|
||||||
} catch (final UnsupportedEncodingException e) {
|
|
||||||
Logger.getLogger(OXPullProvider.class.getName()).log(Level.SEVERE, null, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.io.IOUtils;
|
||||||
|
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
||||||
|
|
||||||
|
import jakarta.activation.DataSource;
|
||||||
|
|
||||||
|
// Copied from PDFBox preflight 2.0.x
|
||||||
|
final class ByteArrayDataSource implements DataSource
|
||||||
|
{
|
||||||
|
private ByteArrayOutputStream data;
|
||||||
|
private String type = null;
|
||||||
|
private String name = null;
|
||||||
|
|
||||||
|
public ByteArrayDataSource (InputStream is) throws IOException
|
||||||
|
{
|
||||||
|
data = new ByteArrayOutputStream ();
|
||||||
|
IOUtils.copy (is, data);
|
||||||
|
IOUtils.closeQuietly (is);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType ()
|
||||||
|
{
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type
|
||||||
|
* the type to set
|
||||||
|
*/
|
||||||
|
public void setType (String type)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name
|
||||||
|
* the name to set
|
||||||
|
*/
|
||||||
|
public void setName (String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream () throws IOException
|
||||||
|
{
|
||||||
|
return new ByteArrayInputStream (data.toByteArray ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName ()
|
||||||
|
{
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputStream getOutputStream () throws IOException
|
||||||
|
{
|
||||||
|
this.data = new ByteArrayOutputStream ();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to create an API similar to the 2.x one
|
||||||
|
final class PreflightParserHelper
|
||||||
|
{
|
||||||
|
private static File createTmpFile (InputStream input) throws IOException
|
||||||
|
{
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File tmpFile = File.createTempFile ("mustang-pdf", ".pdf");
|
||||||
|
fos = new FileOutputStream (tmpFile);
|
||||||
|
IOUtils.copy (input, fos);
|
||||||
|
return tmpFile;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IOUtils.closeQuietly (input);
|
||||||
|
IOUtils.closeQuietly (fos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PreflightParser createPreflightParser (DataSource dataSource) throws IOException
|
||||||
|
{
|
||||||
|
return new PreflightParser (createTmpFile (dataSource.getInputStream ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class PDFBoxUpdateMitigation
|
||||||
|
{
|
||||||
|
// Dummy for the name only
|
||||||
|
}
|
||||||
@@ -20,12 +20,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import org.mustangproject.EStandard;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.mustangproject.EStandard;
|
||||||
|
|
||||||
public class Profiles {
|
public class Profiles {
|
||||||
static Map<String, Profile> zf2Map = Stream.of(new Object[][]{
|
static Map<String, Profile> zf2Map = Stream.of(new Object[][]{
|
||||||
{"MINIMUM", new Profile("MINIMUM", "urn:factur-x.eu:1p0:minimum")},
|
{"MINIMUM", new Profile("MINIMUM", "urn:factur-x.eu:1p0:minimum")},
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* the invoice total with VAT, corrected by prepaid amount, allowances and
|
* the invoice total with VAT, allowances and
|
||||||
* charges
|
* charges, WITHOUT considering prepaid amount
|
||||||
*
|
*
|
||||||
* @return the invoice total including taxes
|
* @return the invoice total including taxes
|
||||||
*/
|
*/
|
||||||
@@ -172,6 +172,10 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
|
|||||||
LineCalculator lc = new LineCalculator(currentItem);
|
LineCalculator lc = new LineCalculator(currentItem);
|
||||||
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(),
|
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(),
|
||||||
currentItem.getProduct().getTaxCategoryCode(), vatDueDateTypeCode);
|
currentItem.getProduct().getTaxCategoryCode(), vatDueDateTypeCode);
|
||||||
|
String reasonText=currentItem.getProduct().getTaxExemptionReason();
|
||||||
|
if (reasonText!=null) {
|
||||||
|
itemVATAmount.setVatExemptionReasonText(reasonText);
|
||||||
|
}
|
||||||
VATAmount current = hm.get(percent.stripTrailingZeros());
|
VATAmount current = hm.get(percent.stripTrailingZeros());
|
||||||
if (current == null) {
|
if (current == null) {
|
||||||
hm.put(percent.stripTrailingZeros(), itemVATAmount);
|
hm.put(percent.stripTrailingZeros(), itemVATAmount);
|
||||||
|
|||||||
@@ -20,33 +20,23 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
import org.dom4j.Document;
|
import org.dom4j.Document;
|
||||||
import org.dom4j.DocumentException;
|
import org.dom4j.DocumentException;
|
||||||
import org.dom4j.DocumentHelper;
|
import org.dom4j.DocumentHelper;
|
||||||
import org.dom4j.io.OutputFormat;
|
import org.dom4j.io.OutputFormat;
|
||||||
import org.dom4j.io.XMLWriter;
|
import org.dom4j.io.XMLWriter;
|
||||||
import org.mustangproject.EStandard;
|
import org.mustangproject.EStandard;
|
||||||
import org.mustangproject.FileAttachment;
|
|
||||||
import org.mustangproject.TradeParty;
|
|
||||||
import org.mustangproject.XMLTools;
|
import org.mustangproject.XMLTools;
|
||||||
|
import org.slf4j.Logger;
|
||||||
import java.io.IOException;
|
import org.slf4j.LoggerFactory;
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat.DATE;
|
|
||||||
import static org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants.CORRECTEDINVOICE;
|
|
||||||
import static org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants.CATEGORY_CODES_WITH_EXEMPTION_REASON;
|
|
||||||
|
|
||||||
public class UBLDAPullProvider implements IXMLProvider {
|
public class UBLDAPullProvider implements IXMLProvider {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger (UBLDAPullProvider.class);
|
||||||
|
|
||||||
protected IExportableTransaction trans;
|
protected IExportableTransaction trans;
|
||||||
protected TransactionCalculator calc;
|
protected TransactionCalculator calc;
|
||||||
@@ -96,13 +86,9 @@ public class UBLDAPullProvider implements IXMLProvider {
|
|||||||
}
|
}
|
||||||
xml += "</DespatchAdvice>\n";
|
xml += "</DespatchAdvice>\n";
|
||||||
final byte[] ublRaw;
|
final byte[] ublRaw;
|
||||||
try {
|
ublRaw = xml.getBytes(StandardCharsets.UTF_8);
|
||||||
ublRaw = xml.getBytes("UTF-8");
|
|
||||||
|
|
||||||
ublData = XMLTools.removeBOM(ublRaw);
|
ublData = XMLTools.removeBOM(ublRaw);
|
||||||
} catch (final UnsupportedEncodingException e) {
|
|
||||||
Logger.getLogger(UBLDAPullProvider.class.getName()).log(Level.SEVERE, null, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPartyXML(IZUGFeRDExportableTradeParty tp) {
|
public String getPartyXML(IZUGFeRDExportableTradeParty tp) {
|
||||||
@@ -133,7 +119,7 @@ public class UBLDAPullProvider implements IXMLProvider {
|
|||||||
try {
|
try {
|
||||||
document = DocumentHelper.parseText(new String(ublData));
|
document = DocumentHelper.parseText(new String(ublData));
|
||||||
} catch (final DocumentException e1) {
|
} catch (final DocumentException e1) {
|
||||||
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e1);
|
LOGGER.error ("Failed to parse UBL", e1);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final OutputFormat format = OutputFormat.createPrettyPrint();
|
final OutputFormat format = OutputFormat.createPrettyPrint();
|
||||||
@@ -143,7 +129,7 @@ public class UBLDAPullProvider implements IXMLProvider {
|
|||||||
res = sw.toString().getBytes(StandardCharsets.UTF_8);
|
res = sw.toString().getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e);
|
LOGGER.error ("Failed to write XML", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
@@ -32,6 +32,16 @@ import java.math.RoundingMode;
|
|||||||
*/
|
*/
|
||||||
public class VATAmount {
|
public class VATAmount {
|
||||||
|
|
||||||
|
|
||||||
|
protected BigDecimal basis, calculated, applicablePercent;
|
||||||
|
|
||||||
|
protected String categoryCode;
|
||||||
|
|
||||||
|
protected String vatExemptionReasonText;
|
||||||
|
|
||||||
|
protected String dueDateTypeCode;
|
||||||
|
|
||||||
|
|
||||||
public VATAmount(BigDecimal basis, BigDecimal calculated, String categoryCode) {
|
public VATAmount(BigDecimal basis, BigDecimal calculated, String categoryCode) {
|
||||||
super();
|
super();
|
||||||
this.basis = basis;
|
this.basis = basis;
|
||||||
@@ -48,35 +58,41 @@ public class VATAmount {
|
|||||||
this.dueDateTypeCode = dueDateTypeCode;
|
this.dueDateTypeCode = dueDateTypeCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal basis, calculated, applicablePercent;
|
|
||||||
|
|
||||||
String categoryCode;
|
|
||||||
|
|
||||||
String dueDateTypeCode;
|
|
||||||
|
|
||||||
public BigDecimal getApplicablePercent() {
|
public BigDecimal getApplicablePercent() {
|
||||||
return applicablePercent;
|
return applicablePercent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApplicablePercent(BigDecimal applicablePercent) {
|
public VATAmount setApplicablePercent(BigDecimal applicablePercent) {
|
||||||
|
|
||||||
this.applicablePercent = applicablePercent;
|
this.applicablePercent = applicablePercent;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getBasis() {
|
public BigDecimal getBasis() {
|
||||||
return basis;
|
return basis;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBasis(BigDecimal basis) {
|
public VATAmount setBasis(BigDecimal basis) {
|
||||||
this.basis = basis.setScale(2, RoundingMode.HALF_UP);
|
this.basis = basis.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getCalculated() {
|
public BigDecimal getCalculated() {
|
||||||
return calculated;
|
return calculated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCalculated(BigDecimal calculated) {
|
public VATAmount setCalculated(BigDecimal calculated) {
|
||||||
this.calculated = calculated;
|
this.calculated = calculated;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVatExemptionReasonText() {
|
||||||
|
return vatExemptionReasonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VATAmount setVatExemptionReasonText(String theText) {
|
||||||
|
this.vatExemptionReasonText = theText;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,34 +108,38 @@ public class VATAmount {
|
|||||||
/**
|
/**
|
||||||
* @param documentCode as String
|
* @param documentCode as String
|
||||||
* @deprecated Use {@link #setCategoryCode(String)} instead
|
* @deprecated Use {@link #setCategoryCode(String)} instead
|
||||||
|
* @return fluent setter
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void setDocumentCode(String documentCode) {
|
public VATAmount setDocumentCode(String documentCode) {
|
||||||
this.categoryCode = documentCode;
|
this.categoryCode = documentCode;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCategoryCode() {
|
public String getCategoryCode() {
|
||||||
return categoryCode;
|
return categoryCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCategoryCode(String categoryCode) {
|
public VATAmount setCategoryCode(String categoryCode) {
|
||||||
this.categoryCode = categoryCode;
|
this.categoryCode = categoryCode;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDueDateTypeCode() {
|
public String getDueDateTypeCode() {
|
||||||
return dueDateTypeCode;
|
return dueDateTypeCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDueDateTypeCode(String dueDateTypeCode) {
|
public VATAmount setDueDateTypeCode(String dueDateTypeCode) {
|
||||||
this.dueDateTypeCode = dueDateTypeCode;
|
this.dueDateTypeCode = dueDateTypeCode;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VATAmount add(VATAmount v) {
|
public VATAmount add(VATAmount v) {
|
||||||
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode, this.dueDateTypeCode);
|
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode, this.dueDateTypeCode).setVatExemptionReasonText(v.getVatExemptionReasonText());
|
||||||
}
|
}
|
||||||
|
|
||||||
public VATAmount subtract(VATAmount v) {
|
public VATAmount subtract(VATAmount v) {
|
||||||
return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.categoryCode, this.dueDateTypeCode);
|
return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.categoryCode, this.dueDateTypeCode).setVatExemptionReasonText(v.getVatExemptionReasonText());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,20 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import javax.xml.transform.*;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import javax.xml.transform.Source;
|
||||||
|
import javax.xml.transform.Templates;
|
||||||
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
import javax.xml.transform.TransformerFactory;
|
||||||
|
import javax.xml.transform.URIResolver;
|
||||||
import javax.xml.transform.stream.StreamResult;
|
import javax.xml.transform.stream.StreamResult;
|
||||||
import javax.xml.transform.stream.StreamSource;
|
import javax.xml.transform.stream.StreamSource;
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
@@ -31,9 +42,8 @@ public class XMLUpgrader {
|
|||||||
* @return String the updated XML
|
* @return String the updated XML
|
||||||
* @throws FileNotFoundException if the source could not be found
|
* @throws FileNotFoundException if the source could not be found
|
||||||
* @throws TransformerException if the source could not be transformed
|
* @throws TransformerException if the source could not be transformed
|
||||||
* @throws UnsupportedEncodingException if the source was not utf8
|
|
||||||
*/
|
*/
|
||||||
public String migrateFromV1ToV2(String xmlFilename) throws FileNotFoundException, TransformerException, UnsupportedEncodingException {
|
public String migrateFromV1ToV2(String xmlFilename) throws FileNotFoundException, TransformerException {
|
||||||
/**
|
/**
|
||||||
* *
|
* *
|
||||||
* http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf
|
* http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf
|
||||||
@@ -45,7 +55,7 @@ public class XMLUpgrader {
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
applySchematronXsl(new FileInputStream(xmlFilename), baos);
|
applySchematronXsl(new FileInputStream(xmlFilename), baos);
|
||||||
String res = null;
|
String res = null;
|
||||||
res = baos.toString("UTF-8");
|
res = baos.toString(StandardCharsets.UTF_8);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,15 @@ package org.mustangproject.ZUGFeRD;
|
|||||||
import org.apache.xmpbox.XMPMetadata;
|
import org.apache.xmpbox.XMPMetadata;
|
||||||
import org.apache.xmpbox.XmpConstants;
|
import org.apache.xmpbox.XmpConstants;
|
||||||
import org.apache.xmpbox.schema.PDFAExtensionSchema;
|
import org.apache.xmpbox.schema.PDFAExtensionSchema;
|
||||||
import org.apache.xmpbox.type.*;
|
import org.apache.xmpbox.type.ArrayProperty;
|
||||||
|
import org.apache.xmpbox.type.Attribute;
|
||||||
|
import org.apache.xmpbox.type.Cardinality;
|
||||||
|
import org.apache.xmpbox.type.ChoiceType;
|
||||||
|
import org.apache.xmpbox.type.DefinedStructuredType;
|
||||||
|
import org.apache.xmpbox.type.PDFAPropertyType;
|
||||||
|
import org.apache.xmpbox.type.PDFASchemaType;
|
||||||
|
import org.apache.xmpbox.type.StructuredType;
|
||||||
|
import org.apache.xmpbox.type.TextType;
|
||||||
import org.mustangproject.EStandard;
|
import org.mustangproject.EStandard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,31 +20,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import org.apache.pdfbox.cos.*;
|
import java.io.File;
|
||||||
import org.apache.pdfbox.io.IOUtils;
|
import java.io.FileOutputStream;
|
||||||
import org.apache.pdfbox.pdmodel.*;
|
import java.io.IOException;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
import java.io.OutputStream;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
|
||||||
import org.apache.pdfbox.preflight.PreflightDocument;
|
|
||||||
import org.apache.pdfbox.preflight.exception.ValidationException;
|
|
||||||
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
|
||||||
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
|
|
||||||
import org.apache.xmpbox.XMPMetadata;
|
|
||||||
import org.apache.xmpbox.schema.AdobePDFSchema;
|
|
||||||
import org.apache.xmpbox.schema.DublinCoreSchema;
|
|
||||||
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
|
|
||||||
import org.apache.xmpbox.schema.XMPBasicSchema;
|
|
||||||
import org.apache.xmpbox.type.BadFieldValueException;
|
|
||||||
import org.apache.xmpbox.xml.XmpSerializer;
|
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
|
||||||
import javax.activation.FileDataSource;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class XRExporter implements IExporter {
|
public class XRExporter implements IExporter {
|
||||||
IXMLProvider xmlProvider;
|
IXMLProvider xmlProvider;
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import org.mustangproject.XMLTools;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
import org.mustangproject.XMLTools;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class XRechnungImporter extends ZUGFeRDImporter {
|
public class XRechnungImporter extends ZUGFeRDImporter {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger (XRechnungImporter.class);
|
||||||
|
|
||||||
public XRechnungImporter(byte[] rawXml) {
|
public XRechnungImporter(byte[] rawXml) {
|
||||||
super();
|
super();
|
||||||
@@ -19,7 +19,7 @@ public class XRechnungImporter extends ZUGFeRDImporter {
|
|||||||
setRawXML(rawXml);
|
setRawXML(rawXml);
|
||||||
containsMeta = true;
|
containsMeta = true;
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
|
LOGGER.error ("Failed to set raw XML", e);
|
||||||
throw new ZUGFeRDExportException(e);
|
throw new ZUGFeRDExportException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ public class XRechnungImporter extends ZUGFeRDImporter {
|
|||||||
setRawXML(Files.readAllBytes(Paths.get(filename)));
|
setRawXML(Files.readAllBytes(Paths.get(filename)));
|
||||||
containsMeta = true;
|
containsMeta = true;
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
|
LOGGER.error ("Failed to set raw XML", e);
|
||||||
throw new ZUGFeRDExportException(e);
|
throw new ZUGFeRDExportException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ public class XRechnungImporter extends ZUGFeRDImporter {
|
|||||||
setRawXML(XMLTools.getBytesFromStream(fileinput));
|
setRawXML(XMLTools.getBytesFromStream(fileinput));
|
||||||
containsMeta = true;
|
containsMeta = true;
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
|
LOGGER.error ("Failed to set raw XML", e);
|
||||||
throw new ZUGFeRDExportException(e);
|
throw new ZUGFeRDExportException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import org.dom4j.Document;
|
import org.dom4j.Document;
|
||||||
import org.dom4j.DocumentException;
|
import org.dom4j.DocumentException;
|
||||||
@@ -39,9 +37,11 @@ import org.dom4j.DocumentHelper;
|
|||||||
import org.dom4j.io.OutputFormat;
|
import org.dom4j.io.OutputFormat;
|
||||||
import org.dom4j.io.XMLWriter;
|
import org.dom4j.io.XMLWriter;
|
||||||
import org.mustangproject.XMLTools;
|
import org.mustangproject.XMLTools;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLProvider {
|
public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger (ZUGFeRD1PullProvider.class);
|
||||||
|
|
||||||
//// MAIN CLASS
|
//// MAIN CLASS
|
||||||
|
|
||||||
@@ -93,17 +93,17 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr
|
|||||||
try {
|
try {
|
||||||
document = DocumentHelper.parseText(new String(zugferdData));
|
document = DocumentHelper.parseText(new String(zugferdData));
|
||||||
} catch (final DocumentException e1) {
|
} catch (final DocumentException e1) {
|
||||||
Logger.getLogger(ZUGFeRD1PullProvider.class.getName()).log(Level.SEVERE, null, e1);
|
LOGGER.error ("Failed to parse ZUGFeRD data", e1);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final OutputFormat format = OutputFormat.createPrettyPrint();
|
final OutputFormat format = OutputFormat.createPrettyPrint();
|
||||||
format.setTrimText(false);
|
format.setTrimText(false);
|
||||||
final XMLWriter writer = new XMLWriter(sw, format);
|
final XMLWriter writer = new XMLWriter(sw, format);
|
||||||
writer.write(document);
|
writer.write(document);
|
||||||
res = sw.toString().getBytes("UTF-8");
|
res = sw.toString().getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
Logger.getLogger(ZUGFeRD1PullProvider.class.getName()).log(Level.SEVERE, null, e);
|
LOGGER.error ("Failed to write ZUGFeRD data", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -387,9 +387,10 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider implements IXMLPr
|
|||||||
+ "<ram:LineTotalAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(lc.getItemTotalNetAmount())
|
+ "<ram:LineTotalAmount currencyID=\"" + trans.getCurrency() + "\">" + currencyFormat(lc.getItemTotalNetAmount())
|
||||||
+ "</ram:LineTotalAmount>"
|
+ "</ram:LineTotalAmount>"
|
||||||
+ "</ram:SpecifiedTradeSettlementMonetarySummation>";
|
+ "</ram:SpecifiedTradeSettlementMonetarySummation>";
|
||||||
if (currentItem.getAdditionalReferencedDocumentID() != null) {
|
if (currentItem.getAdditionalReferences() != null) {
|
||||||
|
xml += "<ram:AdditionalReferencedDocument><ram:ID>" + currentItem.getAdditionalReferences()[0].getIssuerAssignedID() + "</ram:ID><ram:TypeCode>130</ram:TypeCode></ram:AdditionalReferencedDocument>";
|
||||||
|
} else if (currentItem.getAdditionalReferencedDocumentID() != null) {
|
||||||
xml += "<ram:AdditionalReferencedDocument><ram:ID>" + currentItem.getAdditionalReferencedDocumentID() + "</ram:ID><ram:TypeCode>130</ram:TypeCode></ram:AdditionalReferencedDocument>";
|
xml += "<ram:AdditionalReferencedDocument><ram:ID>" + currentItem.getAdditionalReferencedDocumentID() + "</ram:ID><ram:TypeCode>130</ram:TypeCode></ram:AdditionalReferencedDocument>";
|
||||||
|
|
||||||
}
|
}
|
||||||
xml += "</ram:SpecifiedSupplyChainTradeSettlement>"
|
xml += "</ram:SpecifiedSupplyChainTradeSettlement>"
|
||||||
+ "<ram:SpecifiedTradeProduct>";
|
+ "<ram:SpecifiedTradeProduct>";
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import static org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants.CATE
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@@ -35,9 +34,8 @@ import java.util.Base64;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.dom4j.Document;
|
import org.dom4j.Document;
|
||||||
@@ -49,8 +47,11 @@ import org.mustangproject.FileAttachment;
|
|||||||
import org.mustangproject.IncludedNote;
|
import org.mustangproject.IncludedNote;
|
||||||
import org.mustangproject.XMLTools;
|
import org.mustangproject.XMLTools;
|
||||||
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
|
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class ZUGFeRD2PullProvider implements IXMLProvider {
|
public class ZUGFeRD2PullProvider implements IXMLProvider {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRD2PullProvider.class);
|
||||||
|
|
||||||
protected byte[] zugferdData;
|
protected byte[] zugferdData;
|
||||||
protected IExportableTransaction trans;
|
protected IExportableTransaction trans;
|
||||||
@@ -75,11 +76,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String priceFormat(BigDecimal value) {
|
protected String priceFormat(BigDecimal value) {
|
||||||
return XMLTools.nDigitFormat(value, 4);
|
// 18 decimals are max for price and qty due to xml restrictions,
|
||||||
|
// see Chapter 3.2.3 of https://www.w3.org/TR/xmlschema-2/
|
||||||
|
return XMLTools.nDigitFormatDecimalRange(value, 18, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String quantityFormat(BigDecimal value) {
|
protected String quantityFormat(BigDecimal value) {
|
||||||
return XMLTools.nDigitFormat(value, 4);
|
return XMLTools.nDigitFormatDecimalRange(value, 18, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -92,7 +95,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
try {
|
try {
|
||||||
document = DocumentHelper.parseText(new String(zugferdData));
|
document = DocumentHelper.parseText(new String(zugferdData));
|
||||||
} catch (final DocumentException e1) {
|
} catch (final DocumentException e1) {
|
||||||
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e1);
|
LOGGER.error("Failed to parse ZUGFeRD data", e1);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final OutputFormat format = OutputFormat.createPrettyPrint();
|
final OutputFormat format = OutputFormat.createPrettyPrint();
|
||||||
@@ -102,7 +105,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
res = sw.toString().getBytes(StandardCharsets.UTF_8);
|
res = sw.toString().getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e);
|
LOGGER.error("Failed to write ZUGFeRD data", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -137,21 +140,32 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
+ XMLTools.encodeXML(party.getGlobalID()) + "</ram:GlobalID>";
|
+ XMLTools.encodeXML(party.getGlobalID()) + "</ram:GlobalID>";
|
||||||
}
|
}
|
||||||
xml += "<ram:Name>" + XMLTools.encodeXML(party.getName()) + "</ram:Name>";
|
xml += "<ram:Name>" + XMLTools.encodeXML(party.getName()) + "</ram:Name>";
|
||||||
|
if (party.getDescription() != null) {
|
||||||
|
xml += "<ram:Description>" + XMLTools.encodeXML(party.getDescription()) + "</ram:Description>";
|
||||||
|
}
|
||||||
if (party.getLegalOrganisation() != null) {
|
if (party.getLegalOrganisation() != null) {
|
||||||
xml += "<ram:SpecifiedLegalOrganization> ";
|
xml += "<ram:SpecifiedLegalOrganization> ";
|
||||||
xml += " <ram:ID schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemeID()) + "\">" + XMLTools.encodeXML(party.getLegalOrganisation().getID()) + "</ram:ID>";
|
if (party.getLegalOrganisation().getSchemedID() != null) {
|
||||||
|
if (profile == Profiles.getByName("Minimum")) {
|
||||||
|
xml += "<ram:ID>" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "</ram:ID>";
|
||||||
|
} else {
|
||||||
|
xml += "<ram:ID schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getScheme()) + "\">" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "</ram:ID>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (party.getLegalOrganisation().getTradingBusinessName() != null) {
|
||||||
|
xml += "<ram:TradingBusinessName>" + XMLTools.encodeXML(party.getLegalOrganisation().getTradingBusinessName()) + "</ram:TradingBusinessName>";
|
||||||
|
}
|
||||||
xml += "</ram:SpecifiedLegalOrganization>";
|
xml += "</ram:SpecifiedLegalOrganization>";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((party.getContact() != null) && (isSender || profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
|
if ((party.getContact() != null) && (isSender || profile == Profiles.getByName("EN16931") || profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
|
||||||
xml += "<ram:DefinedTradeContact>";
|
xml += "<ram:DefinedTradeContact>";
|
||||||
if (party.getContact().getName() != null) {
|
if (party.getContact().getName() != null) {
|
||||||
xml += "<ram:PersonName>" + XMLTools.encodeXML(party.getContact().getName())
|
xml += "<ram:PersonName>"
|
||||||
|
+ XMLTools.encodeXML(party.getContact().getName())
|
||||||
+ "</ram:PersonName>";
|
+ "</ram:PersonName>";
|
||||||
}
|
}
|
||||||
if (party.getContact().getPhone() != null) {
|
if (party.getContact().getPhone() != null) {
|
||||||
|
|
||||||
xml += "<ram:TelephoneUniversalCommunication><ram:CompleteNumber>"
|
xml += "<ram:TelephoneUniversalCommunication><ram:CompleteNumber>"
|
||||||
+ XMLTools.encodeXML(party.getContact().getPhone()) + "</ram:CompleteNumber>"
|
+ XMLTools.encodeXML(party.getContact().getPhone()) + "</ram:CompleteNumber>"
|
||||||
+ "</ram:TelephoneUniversalCommunication>";
|
+ "</ram:TelephoneUniversalCommunication>";
|
||||||
@@ -192,7 +206,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
+ "</ram:CityName>";
|
+ "</ram:CityName>";
|
||||||
}
|
}
|
||||||
|
|
||||||
//country IS mandatory
|
//country IS mandatory
|
||||||
xml += "<ram:CountryID>" + XMLTools.encodeXML(party.getCountry())
|
xml += "<ram:CountryID>" + XMLTools.encodeXML(party.getCountry())
|
||||||
+ "</ram:CountryID>"
|
+ "</ram:CountryID>"
|
||||||
+ "</ram:PostalTradeAddress>";
|
+ "</ram:PostalTradeAddress>";
|
||||||
@@ -220,6 +234,30 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getTradePartyPayeeAsXML(IZUGFeRDExportableTradeParty party) {
|
||||||
|
String xml = "";
|
||||||
|
// According EN16931 either GlobalID or seller assigned ID might be present for a Payee
|
||||||
|
if (party.getID() != null) {
|
||||||
|
xml += "<ram:ID>" + XMLTools.encodeXML(party.getID()) + "</ram:ID>";
|
||||||
|
}
|
||||||
|
if ((party.getGlobalIDScheme() != null) && (party.getGlobalID() != null)) {
|
||||||
|
xml += "<ram:GlobalID schemeID=\"" + XMLTools.encodeXML(party.getGlobalIDScheme()) + "\">"
|
||||||
|
+ XMLTools.encodeXML(party.getGlobalID())
|
||||||
|
+ "</ram:GlobalID>";
|
||||||
|
}
|
||||||
|
xml += "<ram:Name>" + XMLTools.encodeXML(party.getName()) + "</ram:Name>";
|
||||||
|
|
||||||
|
if (party.getLegalOrganisation() != null) {
|
||||||
|
xml += "<ram:SpecifiedLegalOrganization> ";
|
||||||
|
if (party.getLegalOrganisation().getSchemedID() != null) {
|
||||||
|
xml += "<ram:ID schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getScheme()) + "\">" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "</ram:ID>";
|
||||||
|
}
|
||||||
|
xml += "</ram:SpecifiedLegalOrganization>";
|
||||||
|
}
|
||||||
|
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* returns the XML for a charge or allowance on item level
|
* returns the XML for a charge or allowance on item level
|
||||||
@@ -239,14 +277,19 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String reason = "";
|
String reason = "";
|
||||||
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended"))) {
|
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
|
||||||
// only in extended profile
|
|
||||||
reason = "<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>";
|
reason = "<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>";
|
||||||
}
|
}
|
||||||
|
String reasonCode = "";
|
||||||
|
if ((allowance.getReasonCode() != null) && (profile == Profiles.getByName("XRechnung"))) {
|
||||||
|
// only in XRechnung profile
|
||||||
|
reasonCode = "<ram:ReasonCode>" + allowance.getReasonCode() + "</ram:ReasonCode>";
|
||||||
|
}
|
||||||
final String allowanceChargeStr = "<ram:AppliedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" +
|
final String allowanceChargeStr = "<ram:AppliedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" +
|
||||||
chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage +
|
chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage +
|
||||||
"<ram:ActualAmount>" + priceFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount>" +
|
"<ram:ActualAmount>" + priceFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount>" +
|
||||||
reason +
|
reason +
|
||||||
|
reasonCode +
|
||||||
"</ram:AppliedTradeAllowanceCharge>";
|
"</ram:AppliedTradeAllowanceCharge>";
|
||||||
return allowanceChargeStr;
|
return allowanceChargeStr;
|
||||||
}
|
}
|
||||||
@@ -268,10 +311,20 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
chargeIndicator = "true";
|
chargeIndicator = "true";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String reason = "";
|
||||||
|
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
|
||||||
|
reason = "<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>";
|
||||||
|
}
|
||||||
|
String reasonCode = "";
|
||||||
|
if ((allowance.getReasonCode() != null) && (profile == Profiles.getByName("XRechnung"))) {
|
||||||
|
// only in XRechnung profile
|
||||||
|
reasonCode = "<ram:ReasonCode>" + allowance.getReasonCode() + "</ram:ReasonCode>";
|
||||||
|
}
|
||||||
final String itemTotalAllowanceChargeStr = "<ram:SpecifiedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" +
|
final String itemTotalAllowanceChargeStr = "<ram:SpecifiedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" +
|
||||||
chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage +
|
chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage +
|
||||||
"<ram:ActualAmount>" + currencyFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount>" +
|
"<ram:ActualAmount>" + currencyFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount>" +
|
||||||
"<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>" +
|
reason +
|
||||||
|
reasonCode +
|
||||||
"</ram:SpecifiedTradeAllowanceCharge>";
|
"</ram:SpecifiedTradeAllowanceCharge>";
|
||||||
return itemTotalAllowanceChargeStr;
|
return itemTotalAllowanceChargeStr;
|
||||||
}
|
}
|
||||||
@@ -290,11 +343,22 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
paymentTermsDescription = XMLTools.encodeXML(trans.getPaymentTermDescription());
|
paymentTermsDescription = XMLTools.encodeXML(trans.getPaymentTermDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((paymentTermsDescription == null) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CORRECTEDINVOICE) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)) {
|
|
||||||
paymentTermsDescription = "Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate());
|
|
||||||
|
|
||||||
|
if ((profile == Profiles.getByName("XRechnung")) && (trans.getCashDiscounts() != null) && (trans.getCashDiscounts().length > 0)) {
|
||||||
|
for (IZUGFeRDCashDiscount discount : trans.getCashDiscounts()
|
||||||
|
) {
|
||||||
|
if (paymentTermsDescription == null) {
|
||||||
|
paymentTermsDescription = "";
|
||||||
|
}
|
||||||
|
paymentTermsDescription += discount.getAsXRechnung();
|
||||||
|
}
|
||||||
|
} else if ((paymentTermsDescription == null) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CORRECTEDINVOICE) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)) {
|
||||||
|
if (trans.getDueDate() != null) {
|
||||||
|
paymentTermsDescription = "Please remit until " + germanDateFormat.format(trans.getDueDate());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String typecode = "380";
|
String typecode = "380";
|
||||||
if (trans.getDocumentCode() != null) {
|
if (trans.getDocumentCode() != null) {
|
||||||
typecode = trans.getDocumentCode();
|
typecode = trans.getDocumentCode();
|
||||||
@@ -314,9 +378,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
//
|
//
|
||||||
|
|
||||||
if (getProfile() == Profiles.getByName("XRechnung")) {
|
if (getProfile() == Profiles.getByName("XRechnung")) {
|
||||||
xml += " <ram:BusinessProcessSpecifiedDocumentContextParameter>\n"
|
xml += "<ram:BusinessProcessSpecifiedDocumentContextParameter>\n"
|
||||||
+ " <ram:ID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</ram:ID>\n"
|
+ "<ram:ID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</ram:ID>\n"
|
||||||
+ " </ram:BusinessProcessSpecifiedDocumentContextParameter>\n";
|
+ "</ram:BusinessProcessSpecifiedDocumentContextParameter>\n";
|
||||||
}
|
}
|
||||||
xml +=
|
xml +=
|
||||||
"<ram:GuidelineSpecifiedDocumentContextParameter>"
|
"<ram:GuidelineSpecifiedDocumentContextParameter>"
|
||||||
@@ -325,7 +389,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
+ "</rsm:ExchangedDocumentContext>"
|
+ "</rsm:ExchangedDocumentContext>"
|
||||||
+ "<rsm:ExchangedDocument>"
|
+ "<rsm:ExchangedDocument>"
|
||||||
+ "<ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>"
|
+ "<ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>"
|
||||||
// + " <ram:Name>RECHNUNG</ram:Name>"
|
// + "<ram:Name>RECHNUNG</ram:Name>"
|
||||||
// + "<ram:TypeCode>380</ram:TypeCode>"
|
// + "<ram:TypeCode>380</ram:TypeCode>"
|
||||||
+ "<ram:TypeCode>" + typecode + "</ram:TypeCode>"
|
+ "<ram:TypeCode>" + typecode + "</ram:TypeCode>"
|
||||||
+ "<ram:IssueDateTime>"
|
+ "<ram:IssueDateTime>"
|
||||||
@@ -387,6 +451,33 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
XMLTools.encodeXML(currentItem.getProduct().getDescription()) +
|
XMLTools.encodeXML(currentItem.getProduct().getDescription()) +
|
||||||
"</ram:Description>";
|
"</ram:Description>";
|
||||||
}
|
}
|
||||||
|
if (currentItem.getProduct().getClassifications() != null && currentItem.getProduct().getClassifications().length > 0) {
|
||||||
|
for (IDesignatedProductClassification classification : currentItem.getProduct().getClassifications()) {
|
||||||
|
xml += "<ram:DesignatedProductClassification>"
|
||||||
|
+ "<ram:ClassCode listId=\"" + XMLTools.encodeXML(classification.getClassCode().getListID()) + "\"";
|
||||||
|
if (classification.getClassCode().getListVersionID() != null) {
|
||||||
|
xml += " listVersionID=\"" + XMLTools.encodeXML(classification.getClassCode().getListVersionID()) + "\"";
|
||||||
|
}
|
||||||
|
xml += ">" + classification.getClassCode().getCode() + "</ram:ClassCode>";
|
||||||
|
if (classification.getClassName() != null) {
|
||||||
|
xml += "<ram:ClassName>" + XMLTools.encodeXML(classification.getClassName()) + "</ram:ClassName>";
|
||||||
|
}
|
||||||
|
xml += "</ram:DesignatedProductClassification>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentItem.getProduct().getAttributes() != null) {
|
||||||
|
for (Entry<String, String> entry : currentItem.getProduct().getAttributes().entrySet()) {
|
||||||
|
xml += "<ram:ApplicableProductCharacteristic>" +
|
||||||
|
"<ram:Description>" + XMLTools.encodeXML(entry.getKey()) + "</ram:Description>" +
|
||||||
|
"<ram:Value>" + XMLTools.encodeXML(entry.getValue()) + "</ram:Value>" +
|
||||||
|
"</ram:ApplicableProductCharacteristic>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentItem.getProduct().getCountryOfOrigin() != null) {
|
||||||
|
xml += "<ram:OriginTradeCountry><ram:ID>" +
|
||||||
|
XMLTools.encodeXML(currentItem.getProduct().getCountryOfOrigin()) +
|
||||||
|
"</ram:ID></ram:OriginTradeCountry>";
|
||||||
|
}
|
||||||
xml += "</ram:SpecifiedTradeProduct>"
|
xml += "</ram:SpecifiedTradeProduct>"
|
||||||
|
|
||||||
+ "<ram:SpecifiedLineTradeAgreement>";
|
+ "<ram:SpecifiedLineTradeAgreement>";
|
||||||
@@ -412,11 +503,11 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
+ "<ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit())
|
+ "<ram:BasisQuantity unitCode=\"" + XMLTools.encodeXML(currentItem.getProduct().getUnit())
|
||||||
+ "\">" + quantityFormat(currentItem.getBasisQuantity()) + "</ram:BasisQuantity>"
|
+ "\">" + quantityFormat(currentItem.getBasisQuantity()) + "</ram:BasisQuantity>"
|
||||||
+ allowanceChargeStr
|
+ allowanceChargeStr
|
||||||
// + " <AppliedTradeAllowanceCharge>"
|
// + "<AppliedTradeAllowanceCharge>"
|
||||||
// + " <ChargeIndicator>false</ChargeIndicator>"
|
// + "<ChargeIndicator>false</ChargeIndicator>"
|
||||||
// + " <ActualAmount currencyID=\"EUR\">0.6667</ActualAmount>"
|
// + "<ActualAmount currencyID=\"EUR\">0.6667</ActualAmount>"
|
||||||
// + " <Reason>Rabatt</Reason>"
|
// + "<Reason>Rabatt</Reason>"
|
||||||
// + " </AppliedTradeAllowanceCharge>"
|
// + "</AppliedTradeAllowanceCharge>"
|
||||||
+ "</ram:GrossPriceProductTradePrice>";
|
+ "</ram:GrossPriceProductTradePrice>";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,9 +547,16 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
+ "<ram:LineTotalAmount>" + currencyFormat(lc.getItemTotalNetAmount())
|
+ "<ram:LineTotalAmount>" + currencyFormat(lc.getItemTotalNetAmount())
|
||||||
+ "</ram:LineTotalAmount>" // currencyID=\"EUR\"
|
+ "</ram:LineTotalAmount>" // currencyID=\"EUR\"
|
||||||
+ "</ram:SpecifiedTradeSettlementLineMonetarySummation>";
|
+ "</ram:SpecifiedTradeSettlementLineMonetarySummation>";
|
||||||
if (currentItem.getAdditionalReferencedDocumentID() != null) {
|
if (currentItem.getAdditionalReferences() != null) {
|
||||||
|
for (final IReferencedDocument currentReference : currentItem.getAdditionalReferences()) {
|
||||||
|
xml += "<ram:AdditionalReferencedDocument>" +
|
||||||
|
"<ram:IssuerAssignedID>" + XMLTools.encodeXML(currentReference.getIssuerAssignedID()) + "</ram:IssuerAssignedID>" +
|
||||||
|
"<ram:TypeCode>130</ram:TypeCode>" +
|
||||||
|
"<ram:ReferenceTypeCode>" + XMLTools.encodeXML(currentReference.getReferenceTypeCode()) + "</ram:ReferenceTypeCode>" +
|
||||||
|
"</ram:AdditionalReferencedDocument>";
|
||||||
|
}
|
||||||
|
} else if (currentItem.getAdditionalReferencedDocumentID() != null) {
|
||||||
xml += "<ram:AdditionalReferencedDocument><ram:IssuerAssignedID>" + currentItem.getAdditionalReferencedDocumentID() + "</ram:IssuerAssignedID><ram:TypeCode>130</ram:TypeCode></ram:AdditionalReferencedDocument>";
|
xml += "<ram:AdditionalReferencedDocument><ram:IssuerAssignedID>" + currentItem.getAdditionalReferencedDocumentID() + "</ram:IssuerAssignedID><ram:TypeCode>130</ram:TypeCode></ram:AdditionalReferencedDocument>";
|
||||||
|
|
||||||
}
|
}
|
||||||
xml += "</ram:SpecifiedLineTradeSettlement>"
|
xml += "</ram:SpecifiedLineTradeSettlement>"
|
||||||
+ "</ram:IncludedSupplyChainTradeLineItem>";
|
+ "</ram:IncludedSupplyChainTradeLineItem>";
|
||||||
@@ -475,53 +573,53 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
+ getTradePartyAsXML(trans.getSender(), true, false)
|
+ getTradePartyAsXML(trans.getSender(), true, false)
|
||||||
+ "</ram:SellerTradeParty>"
|
+ "</ram:SellerTradeParty>"
|
||||||
+ "<ram:BuyerTradeParty>";
|
+ "<ram:BuyerTradeParty>";
|
||||||
// + " <ID>GE2020211</ID>"
|
// + "<ID>GE2020211</ID>"
|
||||||
// + " <GlobalID schemeID=\"0088\">4000001987658</GlobalID>"
|
// + "<GlobalID schemeID=\"0088\">4000001987658</GlobalID>"
|
||||||
|
|
||||||
xml += getTradePartyAsXML(trans.getRecipient(), false, false);
|
xml += getTradePartyAsXML(trans.getRecipient(), false, false);
|
||||||
xml += "</ram:BuyerTradeParty>";
|
xml += "</ram:BuyerTradeParty>";
|
||||||
|
|
||||||
if (trans.getSellerOrderReferencedDocumentID() != null) {
|
if (trans.getSellerOrderReferencedDocumentID() != null) {
|
||||||
xml += " <ram:SellerOrderReferencedDocument>"
|
xml += "<ram:SellerOrderReferencedDocument>"
|
||||||
+ " <ram:IssuerAssignedID>"
|
+ "<ram:IssuerAssignedID>"
|
||||||
+ XMLTools.encodeXML(trans.getSellerOrderReferencedDocumentID()) + "</ram:IssuerAssignedID>"
|
+ XMLTools.encodeXML(trans.getSellerOrderReferencedDocumentID()) + "</ram:IssuerAssignedID>"
|
||||||
+ " </ram:SellerOrderReferencedDocument>";
|
+ "</ram:SellerOrderReferencedDocument>";
|
||||||
}
|
}
|
||||||
if (trans.getBuyerOrderReferencedDocumentID() != null) {
|
if (trans.getBuyerOrderReferencedDocumentID() != null) {
|
||||||
xml += " <ram:BuyerOrderReferencedDocument>"
|
xml += "<ram:BuyerOrderReferencedDocument>"
|
||||||
+ " <ram:IssuerAssignedID>"
|
+ "<ram:IssuerAssignedID>"
|
||||||
+ XMLTools.encodeXML(trans.getBuyerOrderReferencedDocumentID()) + "</ram:IssuerAssignedID>"
|
+ XMLTools.encodeXML(trans.getBuyerOrderReferencedDocumentID()) + "</ram:IssuerAssignedID>"
|
||||||
+ " </ram:BuyerOrderReferencedDocument>";
|
+ "</ram:BuyerOrderReferencedDocument>";
|
||||||
}
|
}
|
||||||
if (trans.getContractReferencedDocument() != null) {
|
if (trans.getContractReferencedDocument() != null) {
|
||||||
xml += " <ram:ContractReferencedDocument>"
|
xml += "<ram:ContractReferencedDocument>"
|
||||||
+ " <ram:IssuerAssignedID>"
|
+ "<ram:IssuerAssignedID>"
|
||||||
+ XMLTools.encodeXML(trans.getContractReferencedDocument()) + "</ram:IssuerAssignedID>"
|
+ XMLTools.encodeXML(trans.getContractReferencedDocument()) + "</ram:IssuerAssignedID>"
|
||||||
+ " </ram:ContractReferencedDocument>";
|
+ "</ram:ContractReferencedDocument>";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additional Documents of XRechnung (Rechnungsbegruendende Unterlagen - BG-24 XRechnung)
|
// Additional Documents of XRechnung (Rechnungsbegruendende Unterlagen - BG-24 XRechnung)
|
||||||
if (trans.getAdditionalReferencedDocuments() != null) {
|
if (trans.getAdditionalReferencedDocuments() != null) {
|
||||||
for (final FileAttachment f : trans.getAdditionalReferencedDocuments()) {
|
for (final FileAttachment f : trans.getAdditionalReferencedDocuments()) {
|
||||||
final String documentContent = new String(Base64.getEncoder().encodeToString(f.getData()));
|
final String documentContent = new String(Base64.getEncoder().encodeToString(f.getData()));
|
||||||
xml += " <ram:AdditionalReferencedDocument>"
|
xml += "<ram:AdditionalReferencedDocument>"
|
||||||
+ " <ram:IssuerAssignedID>" + f.getFilename() + "</ram:IssuerAssignedID>"
|
+ "<ram:IssuerAssignedID>" + f.getFilename() + "</ram:IssuerAssignedID>"
|
||||||
+ " <ram:TypeCode>916</ram:TypeCode>"
|
+ "<ram:TypeCode>916</ram:TypeCode>"
|
||||||
+ " <ram:Name>" + f.getDescription() + "</ram:Name>"
|
+ "<ram:Name>" + f.getDescription() + "</ram:Name>"
|
||||||
+ " <ram:AttachmentBinaryObject mimeCode=\"" + f.getMimetype() + "\"\n"
|
+ "<ram:AttachmentBinaryObject mimeCode=\"" + f.getMimetype() + "\"\n"
|
||||||
+ " filename=\"" + f.getFilename() + "\">" + documentContent + "</ram:AttachmentBinaryObject>"
|
+ "filename=\"" + f.getFilename() + "\">" + documentContent + "</ram:AttachmentBinaryObject>"
|
||||||
+ " </ram:AdditionalReferencedDocument>";
|
+ "</ram:AdditionalReferencedDocument>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trans.getSpecifiedProcuringProjectID() != null) {
|
if (trans.getSpecifiedProcuringProjectID() != null) {
|
||||||
xml += " <ram:SpecifiedProcuringProject>"
|
xml += "<ram:SpecifiedProcuringProject>"
|
||||||
+ " <ram:ID>"
|
+ "<ram:ID>"
|
||||||
+ XMLTools.encodeXML(trans.getSpecifiedProcuringProjectID()) + "</ram:ID>";
|
+ XMLTools.encodeXML(trans.getSpecifiedProcuringProjectID()) + "</ram:ID>";
|
||||||
if (trans.getSpecifiedProcuringProjectName() != null) {
|
if (trans.getSpecifiedProcuringProjectName() != null) {
|
||||||
xml += " <ram:Name >" + XMLTools.encodeXML(trans.getSpecifiedProcuringProjectName()) + "</ram:Name>";
|
xml += "<ram:Name>" + XMLTools.encodeXML(trans.getSpecifiedProcuringProjectName()) + "</ram:Name>";
|
||||||
}
|
}
|
||||||
xml += " </ram:SpecifiedProcuringProject>";
|
xml += "</ram:SpecifiedProcuringProject>";
|
||||||
}
|
}
|
||||||
xml += "</ram:ApplicableHeaderTradeAgreement>";
|
xml += "</ram:ApplicableHeaderTradeAgreement>";
|
||||||
xml += "<ram:ApplicableHeaderTradeDelivery>";
|
xml += "<ram:ApplicableHeaderTradeDelivery>";
|
||||||
@@ -538,12 +636,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
+ "<ram:OccurrenceDateTime>";
|
+ "<ram:OccurrenceDateTime>";
|
||||||
xml += DATE.udtFormat(trans.getDeliveryDate());
|
xml += DATE.udtFormat(trans.getDeliveryDate());
|
||||||
xml += "</ram:OccurrenceDateTime>";
|
xml += "</ram:OccurrenceDateTime>";
|
||||||
xml += " </ram:ActualDeliverySupplyChainEvent>";
|
xml += "</ram:ActualDeliverySupplyChainEvent>";
|
||||||
|
|
||||||
} else {
|
|
||||||
if ((trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE) && (getProfile() != Profiles.getByName("Minimum"))) {
|
|
||||||
throw new IllegalStateException("No delivery date provided");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* + "<DeliveryNoteReferencedDocument>" +
|
* + "<DeliveryNoteReferencedDocument>" +
|
||||||
@@ -560,10 +654,19 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
|
|
||||||
xml += "</ram:ApplicableHeaderTradeDelivery>";
|
xml += "</ram:ApplicableHeaderTradeDelivery>";
|
||||||
xml += "<ram:ApplicableHeaderTradeSettlement>";
|
xml += "<ram:ApplicableHeaderTradeSettlement>";
|
||||||
if ((trans.getNumber() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
|
|
||||||
xml += " <ram:PaymentReference>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:PaymentReference>";
|
if ((trans.getCreditorReferenceID() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
|
||||||
|
xml += "<ram:CreditorReferenceID>" + XMLTools.encodeXML(trans.getCreditorReferenceID()) + "</ram:CreditorReferenceID>";
|
||||||
|
}
|
||||||
|
if ((trans.getNumber() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
|
||||||
|
xml += "<ram:PaymentReference>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:PaymentReference>";
|
||||||
|
}
|
||||||
|
xml += "<ram:InvoiceCurrencyCode>" + trans.getCurrency() + "</ram:InvoiceCurrencyCode>";
|
||||||
|
if (this.trans.getPayee() != null) {
|
||||||
|
xml += "<ram:PayeeTradeParty>" +
|
||||||
|
getTradePartyPayeeAsXML(this.trans.getPayee()) +
|
||||||
|
"</ram:PayeeTradeParty>";
|
||||||
}
|
}
|
||||||
xml += " <ram:InvoiceCurrencyCode>" + trans.getCurrency() + "</ram:InvoiceCurrencyCode>";
|
|
||||||
|
|
||||||
if (trans.getTradeSettlementPayment() != null) {
|
if (trans.getTradeSettlementPayment() != null) {
|
||||||
for (final IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) {
|
for (final IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) {
|
||||||
@@ -599,12 +702,17 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
final String amountDueDateTypeCode = amount.getDueDateTypeCode();
|
final String amountDueDateTypeCode = amount.getDueDateTypeCode();
|
||||||
final boolean displayExemptionReason = CATEGORY_CODES_WITH_EXEMPTION_REASON.contains(amountCategoryCode);
|
final boolean displayExemptionReason = CATEGORY_CODES_WITH_EXEMPTION_REASON.contains(amountCategoryCode);
|
||||||
if (getProfile() != Profiles.getByName("Minimum")) {
|
if (getProfile() != Profiles.getByName("Minimum")) {
|
||||||
|
String exemptionReasonTextXML = "";
|
||||||
|
if ((displayExemptionReason) && (amount.getVatExemptionReasonText() != null)) {
|
||||||
|
exemptionReasonTextXML = "<ram:ExemptionReason>" + XMLTools.encodeXML(amount.getVatExemptionReasonText()) + "</ram:ExemptionReason>";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
xml += "<ram:ApplicableTradeTax>"
|
xml += "<ram:ApplicableTradeTax>"
|
||||||
+ "<ram:CalculatedAmount>" + currencyFormat(amount.getCalculated())
|
+ "<ram:CalculatedAmount>" + currencyFormat(amount.getCalculated())
|
||||||
+ "</ram:CalculatedAmount>" //currencyID=\"EUR\"
|
+ "</ram:CalculatedAmount>" //currencyID=\"EUR\"
|
||||||
+ "<ram:TypeCode>VAT</ram:TypeCode>"
|
+ "<ram:TypeCode>VAT</ram:TypeCode>"
|
||||||
+ (displayExemptionReason ? exemptionReason : "")
|
+ exemptionReasonTextXML
|
||||||
+ "<ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>" // currencyID=\"EUR\"
|
+ "<ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>" // currencyID=\"EUR\"
|
||||||
+ "<ram:CategoryCode>" + amountCategoryCode + "</ram:CategoryCode>"
|
+ "<ram:CategoryCode>" + amountCategoryCode + "</ram:CategoryCode>"
|
||||||
+ (amountDueDateTypeCode != null ? "<ram:DueDateTypeCode>" + amountDueDateTypeCode + "</ram:DueDateTypeCode>" : "")
|
+ (amountDueDateTypeCode != null ? "<ram:DueDateTypeCode>" + amountDueDateTypeCode + "</ram:DueDateTypeCode>" : "")
|
||||||
@@ -625,40 +733,87 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((trans.getZFCharges() != null) && (trans.getZFCharges().length > 0)) {
|
if ((trans.getZFCharges() != null) && (trans.getZFCharges().length > 0)) {
|
||||||
|
if (profile == Profiles.getByName("XRechnung")) {
|
||||||
for (final BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
|
for (IZUGFeRDAllowanceCharge charge : trans.getZFCharges()) {
|
||||||
if (calc.getChargesForPercent(currentTaxPercent).compareTo(BigDecimal.ZERO) != 0) {
|
xml += "<ram:SpecifiedTradeAllowanceCharge>" +
|
||||||
xml += " <ram:SpecifiedTradeAllowanceCharge>" +
|
|
||||||
"<ram:ChargeIndicator>" +
|
"<ram:ChargeIndicator>" +
|
||||||
"<udt:Indicator>true</udt:Indicator>" +
|
"<udt:Indicator>true</udt:Indicator>" +
|
||||||
"</ram:ChargeIndicator>" +
|
"</ram:ChargeIndicator>" +
|
||||||
"<ram:ActualAmount>" + currencyFormat(calc.getChargesForPercent(currentTaxPercent)) + "</ram:ActualAmount>" +
|
"<ram:ActualAmount>" + currencyFormat(charge.getTotalAmount(calc)) + "</ram:ActualAmount>";
|
||||||
"<ram:Reason>" + XMLTools.encodeXML(calc.getChargeReasonForPercent(currentTaxPercent)) + "</ram:Reason>" +
|
if (charge.getReason() != null) {
|
||||||
"<ram:CategoryTradeTax>" +
|
xml += "<ram:Reason>" + XMLTools.encodeXML(charge.getReason()) + "</ram:Reason>";
|
||||||
|
}
|
||||||
|
if (charge.getReasonCode() != null) {
|
||||||
|
xml += "<ram:ReasonCode>" + charge.getReasonCode() + "</ram:ReasonCode>";
|
||||||
|
}
|
||||||
|
xml += "<ram:CategoryTradeTax>" +
|
||||||
"<ram:TypeCode>VAT</ram:TypeCode>" +
|
"<ram:TypeCode>VAT</ram:TypeCode>" +
|
||||||
"<ram:CategoryCode>" + VATPercentAmountMap.get(currentTaxPercent).getCategoryCode() + "</ram:CategoryCode>" +
|
"<ram:CategoryCode>" + charge.getCategoryCode() + "</ram:CategoryCode>";
|
||||||
"<ram:RateApplicablePercent>" + vatFormat(currentTaxPercent) + "</ram:RateApplicablePercent>" +
|
if (charge.getTaxPercent() != null) {
|
||||||
"</ram:CategoryTradeTax>" +
|
xml += "<ram:RateApplicablePercent>" + vatFormat(charge.getTaxPercent()) + "</ram:RateApplicablePercent>";
|
||||||
"</ram:SpecifiedTradeAllowanceCharge> ";
|
}
|
||||||
|
xml += "</ram:CategoryTradeTax>" +
|
||||||
|
"</ram:SpecifiedTradeAllowanceCharge>";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (final BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
|
||||||
|
if (calc.getChargesForPercent(currentTaxPercent).compareTo(BigDecimal.ZERO) != 0) {
|
||||||
|
xml += "<ram:SpecifiedTradeAllowanceCharge>" +
|
||||||
|
"<ram:ChargeIndicator>" +
|
||||||
|
"<udt:Indicator>true</udt:Indicator>" +
|
||||||
|
"</ram:ChargeIndicator>" +
|
||||||
|
"<ram:ActualAmount>" + currencyFormat(calc.getChargesForPercent(currentTaxPercent)) + "</ram:ActualAmount>" +
|
||||||
|
"<ram:Reason>" + XMLTools.encodeXML(calc.getChargeReasonForPercent(currentTaxPercent)) + "</ram:Reason>" +
|
||||||
|
"<ram:CategoryTradeTax>" +
|
||||||
|
"<ram:TypeCode>VAT</ram:TypeCode>" +
|
||||||
|
"<ram:CategoryCode>" + VATPercentAmountMap.get(currentTaxPercent).getCategoryCode() + "</ram:CategoryCode>" +
|
||||||
|
"<ram:RateApplicablePercent>" + vatFormat(currentTaxPercent) + "</ram:RateApplicablePercent>" +
|
||||||
|
"</ram:CategoryTradeTax>" +
|
||||||
|
"</ram:SpecifiedTradeAllowanceCharge>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((trans.getZFAllowances() != null) && (trans.getZFAllowances().length > 0)) {
|
if ((trans.getZFAllowances() != null) && (trans.getZFAllowances().length > 0)) {
|
||||||
for (final BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
|
if (profile == Profiles.getByName("XRechnung")) {
|
||||||
if (calc.getAllowancesForPercent(currentTaxPercent).compareTo(BigDecimal.ZERO) != 0) {
|
for (IZUGFeRDAllowanceCharge allowance : trans.getZFAllowances()) {
|
||||||
xml += "<ram:SpecifiedTradeAllowanceCharge>" +
|
xml += "<ram:SpecifiedTradeAllowanceCharge>" +
|
||||||
"<ram:ChargeIndicator>" +
|
"<ram:ChargeIndicator>" +
|
||||||
"<udt:Indicator>false</udt:Indicator>" +
|
"<udt:Indicator>false</udt:Indicator>" +
|
||||||
"</ram:ChargeIndicator>" +
|
"</ram:ChargeIndicator>" +
|
||||||
"<ram:ActualAmount>" + currencyFormat(calc.getAllowancesForPercent(currentTaxPercent)) + "</ram:ActualAmount>" +
|
"<ram:ActualAmount>" + currencyFormat(allowance.getTotalAmount(calc)) + "</ram:ActualAmount>";
|
||||||
"<ram:Reason>" + XMLTools.encodeXML(calc.getAllowanceReasonForPercent(currentTaxPercent)) + "</ram:Reason>" +
|
if (allowance.getReason() != null) {
|
||||||
"<ram:CategoryTradeTax>" +
|
xml += "<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>";
|
||||||
|
}
|
||||||
|
if (allowance.getReasonCode() != null) {
|
||||||
|
xml += "<ram:ReasonCode>" + allowance.getReasonCode() + "</ram:ReasonCode>";
|
||||||
|
}
|
||||||
|
xml += "<ram:CategoryTradeTax>" +
|
||||||
"<ram:TypeCode>VAT</ram:TypeCode>" +
|
"<ram:TypeCode>VAT</ram:TypeCode>" +
|
||||||
"<ram:CategoryCode>" + VATPercentAmountMap.get(currentTaxPercent).getCategoryCode() + "</ram:CategoryCode>" +
|
"<ram:CategoryCode>" + allowance.getCategoryCode() + "</ram:CategoryCode>";
|
||||||
"<ram:RateApplicablePercent>" + vatFormat(currentTaxPercent) + "</ram:RateApplicablePercent>" +
|
if (allowance.getTaxPercent() != null) {
|
||||||
"</ram:CategoryTradeTax>" +
|
xml += "<ram:RateApplicablePercent>" + vatFormat(allowance.getTaxPercent()) + "</ram:RateApplicablePercent>";
|
||||||
"</ram:SpecifiedTradeAllowanceCharge> ";
|
}
|
||||||
|
xml += "</ram:CategoryTradeTax>" +
|
||||||
|
"</ram:SpecifiedTradeAllowanceCharge>";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (final BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
|
||||||
|
if (calc.getAllowancesForPercent(currentTaxPercent).compareTo(BigDecimal.ZERO) != 0) {
|
||||||
|
xml += "<ram:SpecifiedTradeAllowanceCharge>" +
|
||||||
|
"<ram:ChargeIndicator>" +
|
||||||
|
"<udt:Indicator>false</udt:Indicator>" +
|
||||||
|
"</ram:ChargeIndicator>" +
|
||||||
|
"<ram:ActualAmount>" + currencyFormat(calc.getAllowancesForPercent(currentTaxPercent)) + "</ram:ActualAmount>" +
|
||||||
|
"<ram:Reason>" + XMLTools.encodeXML(calc.getAllowanceReasonForPercent(currentTaxPercent)) + "</ram:Reason>" +
|
||||||
|
"<ram:CategoryTradeTax>" +
|
||||||
|
"<ram:TypeCode>VAT</ram:TypeCode>" +
|
||||||
|
"<ram:CategoryCode>" + VATPercentAmountMap.get(currentTaxPercent).getCategoryCode() + "</ram:CategoryCode>" +
|
||||||
|
"<ram:RateApplicablePercent>" + vatFormat(currentTaxPercent) + "</ram:RateApplicablePercent>" +
|
||||||
|
"</ram:CategoryTradeTax>" +
|
||||||
|
"</ram:SpecifiedTradeAllowanceCharge>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -689,6 +844,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
} else {
|
} else {
|
||||||
xml += buildPaymentTermsXml();
|
xml += buildPaymentTermsXml();
|
||||||
}
|
}
|
||||||
|
if ((profile == Profiles.getByName("Extended")) && (trans.getCashDiscounts() != null) && (trans.getCashDiscounts().length > 0)) {
|
||||||
|
for (IZUGFeRDCashDiscount discount : trans.getCashDiscounts()
|
||||||
|
) {
|
||||||
|
xml += discount.getAsCII();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
final String allowanceTotalLine = "<ram:AllowanceTotalAmount>" + currencyFormat(calc.getAllowancesForPercent(null)) + "</ram:AllowanceTotalAmount>";
|
final String allowanceTotalLine = "<ram:AllowanceTotalAmount>" + currencyFormat(calc.getAllowancesForPercent(null)) + "</ram:AllowanceTotalAmount>";
|
||||||
@@ -710,43 +871,39 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
// //
|
// //
|
||||||
// currencyID=\"EUR\"
|
// currencyID=\"EUR\"
|
||||||
if (getProfile() != Profiles.getByName("Minimum")) {
|
if (getProfile() != Profiles.getByName("Minimum")) {
|
||||||
xml += " <ram:TotalPrepaidAmount>" + currencyFormat(calc.getTotalPrepaid()) + "</ram:TotalPrepaidAmount>";
|
xml += "<ram:TotalPrepaidAmount>" + currencyFormat(calc.getTotalPrepaid()) + "</ram:TotalPrepaidAmount>";
|
||||||
}
|
}
|
||||||
xml += "<ram:DuePayableAmount>" + currencyFormat(calc.getGrandTotal().subtract(calc.getTotalPrepaid())) + "</ram:DuePayableAmount>"
|
xml += "<ram:DuePayableAmount>" + currencyFormat(calc.getGrandTotal().subtract(calc.getTotalPrepaid())) + "</ram:DuePayableAmount>"
|
||||||
+ "</ram:SpecifiedTradeSettlementHeaderMonetarySummation>";
|
+ "</ram:SpecifiedTradeSettlementHeaderMonetarySummation>";
|
||||||
if (trans.getInvoiceReferencedDocumentID() != null) {
|
if (trans.getInvoiceReferencedDocumentID() != null) {
|
||||||
xml += " <ram:InvoiceReferencedDocument>"
|
xml += "<ram:InvoiceReferencedDocument>"
|
||||||
+ " <ram:IssuerAssignedID>"
|
+ "<ram:IssuerAssignedID>"
|
||||||
+ XMLTools.encodeXML(trans.getInvoiceReferencedDocumentID()) + "</ram:IssuerAssignedID>";
|
+ XMLTools.encodeXML(trans.getInvoiceReferencedDocumentID()) + "</ram:IssuerAssignedID>";
|
||||||
if (trans.getInvoiceReferencedIssueDate() != null) {
|
if (trans.getInvoiceReferencedIssueDate() != null) {
|
||||||
xml += "<ram:FormattedIssueDateTime>"
|
xml += "<ram:FormattedIssueDateTime>"
|
||||||
+ DATE.qdtFormat(trans.getInvoiceReferencedIssueDate())
|
+ DATE.qdtFormat(trans.getInvoiceReferencedIssueDate())
|
||||||
+ "</ram:FormattedIssueDateTime>";
|
+ "</ram:FormattedIssueDateTime>";
|
||||||
}
|
}
|
||||||
xml += " </ram:InvoiceReferencedDocument>";
|
xml += "</ram:InvoiceReferencedDocument>";
|
||||||
}
|
}
|
||||||
|
|
||||||
xml += "</ram:ApplicableHeaderTradeSettlement>";
|
xml += "</ram:ApplicableHeaderTradeSettlement>";
|
||||||
// + " <IncludedSupplyChainTradeLineItem>\n"
|
// + "<IncludedSupplyChainTradeLineItem>\n"
|
||||||
// + " <AssociatedDocumentLineDocument>\n"
|
// + "<AssociatedDocumentLineDocument>\n"
|
||||||
// + " <IncludedNote>\n"
|
// + "<IncludedNote>\n"
|
||||||
// + " <Content>Wir erlauben uns Ihnen folgende Positionen aus der Lieferung Nr.
|
// + "<Content>Wir erlauben uns Ihnen folgende Positionen aus der Lieferung Nr.
|
||||||
// 2013-51112 in Rechnung zu stellen:</Content>\n"
|
// 2013-51112 in Rechnung zu stellen:</Content>\n"
|
||||||
// + " </IncludedNote>\n"
|
// + "</IncludedNote>\n"
|
||||||
// + " </AssociatedDocumentLineDocument>\n"
|
// + "</AssociatedDocumentLineDocument>\n"
|
||||||
// + " </IncludedSupplyChainTradeLineItem>\n";
|
// + "</IncludedSupplyChainTradeLineItem>\n";
|
||||||
|
|
||||||
xml += "</rsm:SupplyChainTradeTransaction>"
|
xml += "</rsm:SupplyChainTradeTransaction>"
|
||||||
+ "</rsm:CrossIndustryInvoice>";
|
+ "</rsm:CrossIndustryInvoice>";
|
||||||
|
|
||||||
final byte[] zugferdRaw;
|
final byte[] zugferdRaw;
|
||||||
try {
|
zugferdRaw = xml.getBytes(StandardCharsets.UTF_8);
|
||||||
zugferdRaw = xml.getBytes("UTF-8");
|
|
||||||
|
|
||||||
zugferdData = XMLTools.removeBOM(zugferdRaw);
|
zugferdData = XMLTools.removeBOM(zugferdRaw);
|
||||||
} catch (final UnsupportedEncodingException e) {
|
|
||||||
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String buildItemNotes(IZUGFeRDExportableItem currentItem) {
|
protected String buildItemNotes(IZUGFeRDExportableItem currentItem) {
|
||||||
@@ -760,8 +917,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String buildNotes(IExportableTransaction exportableTransaction) {
|
protected String buildNotes(IExportableTransaction exportableTransaction) {
|
||||||
final List<IncludedNote> includedNotes = Optional.ofNullable(exportableTransaction.getNotesWithSubjectCode())
|
final List<IncludedNote> includedNotes = new ArrayList<>();
|
||||||
.orElse(new ArrayList<>());
|
Optional.ofNullable(exportableTransaction.getNotesWithSubjectCode()).ifPresent(includedNotes::addAll);
|
||||||
|
|
||||||
if (exportableTransaction.getNotes() != null) {
|
if (exportableTransaction.getNotes() != null) {
|
||||||
for (final String currentNote : exportableTransaction.getNotes()) {
|
for (final String currentNote : exportableTransaction.getNotes()) {
|
||||||
includedNotes.add(IncludedNote.unspecifiedNote(currentNote));
|
includedNotes.add(IncludedNote.unspecifiedNote(currentNote));
|
||||||
|
|||||||
@@ -19,25 +19,21 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.apache.pdfbox.preflight.PreflightDocument;
|
import org.apache.pdfbox.preflight.PreflightDocument;
|
||||||
|
import org.apache.pdfbox.preflight.ValidationResult;
|
||||||
import org.apache.pdfbox.preflight.exception.ValidationException;
|
import org.apache.pdfbox.preflight.exception.ValidationException;
|
||||||
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
||||||
import org.mustangproject.EStandard;
|
import org.mustangproject.EStandard;
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
import jakarta.activation.DataSource;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
public class ZUGFeRDExporterFromA1 extends ZUGFeRDExporterFromA3 implements IZUGFeRDExporter {
|
public class ZUGFeRDExporterFromA1 extends ZUGFeRDExporterFromA3 {
|
||||||
protected boolean ignorePDFAErrors = false;
|
|
||||||
|
|
||||||
public ZUGFeRDExporterFromA1 ignorePDFAErrors() {
|
|
||||||
this.ignorePDFAErrors = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isValidA1(DataSource dataSource) throws IOException {
|
private static boolean isValidA1(DataSource dataSource) throws IOException {
|
||||||
return getPDFAParserValidationResult(new PreflightParser(dataSource));
|
return getPDFAParserValidationResult(PreflightParserHelper.createPreflightParser(dataSource));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean getPDFAParserValidationResult(PreflightParser parser) throws IOException {
|
private static boolean getPDFAParserValidationResult(PreflightParser parser) throws IOException {
|
||||||
@@ -46,19 +42,19 @@ public class ZUGFeRDExporterFromA1 extends ZUGFeRDExporterFromA3 implements IZUG
|
|||||||
* NonSequentialParser. Some additional controls are present to check a set of
|
* NonSequentialParser. Some additional controls are present to check a set of
|
||||||
* PDF/A requirements. (Stream length consistency, EOL after some Keyword...)
|
* PDF/A requirements. (Stream length consistency, EOL after some Keyword...)
|
||||||
*/
|
*/
|
||||||
parser.parse();// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
|
// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
|
||||||
|
|
||||||
try (PreflightDocument document = parser.getPreflightDocument()) {
|
try (PreflightDocument document = (PreflightDocument) parser.parse()) {
|
||||||
/*
|
/*
|
||||||
* Once the syntax validation is done, the parser can provide a
|
* Once the syntax validation is done, the parser can provide a
|
||||||
* PreflightDocument (that inherits from PDDocument) This document process the
|
* PreflightDocument (that inherits from PDDocument) This document process the
|
||||||
* end of PDF/A validation.
|
* end of PDF/A validation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
document.validate();
|
ValidationResult res = document.validate();
|
||||||
|
|
||||||
// Get validation result
|
// Get validation result
|
||||||
return document.getResult().isValid();
|
return res.isValid();
|
||||||
} catch (ValidationException e) {
|
} catch (ValidationException e) {
|
||||||
/*
|
/*
|
||||||
* the parse method can throw a SyntaxValidationException if the PDF file can't
|
* the parse method can throw a SyntaxValidationException if the PDF file can't
|
||||||
@@ -70,14 +66,17 @@ public class ZUGFeRDExporterFromA1 extends ZUGFeRDExporterFromA3 implements IZUG
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ZUGFeRDExporterFromA1 setProfile(Profile p) {
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 setProfile(Profile p) {
|
||||||
return (ZUGFeRDExporterFromA1)super.setProfile(p);
|
return (ZUGFeRDExporterFromA1)super.setProfile(p);
|
||||||
}
|
}
|
||||||
public ZUGFeRDExporterFromA1 setProfile(String profileName) {
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 setProfile(String profileName) {
|
||||||
return (ZUGFeRDExporterFromA1)super.setProfile(profileName);
|
return (ZUGFeRDExporterFromA1)super.setProfile(profileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
|
@Override
|
||||||
|
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException {
|
||||||
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
|
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
|
||||||
throw new IOException("File is not a valid PDF/A-1 input file");
|
throw new IOException("File is not a valid PDF/A-1 input file");
|
||||||
}
|
}
|
||||||
@@ -85,35 +84,45 @@ public class ZUGFeRDExporterFromA1 extends ZUGFeRDExporterFromA3 implements IZUG
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ZUGFeRDExporterFromA1 load(String pdfFilename) throws IOException {
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 load(String pdfFilename) throws IOException {
|
||||||
return (ZUGFeRDExporterFromA1) super.load(pdfFilename);
|
return (ZUGFeRDExporterFromA1) super.load(pdfFilename);
|
||||||
}
|
}
|
||||||
public ZUGFeRDExporterFromA1 load(byte[] pdfBinary) throws IOException {
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 load(byte[] pdfBinary) throws IOException {
|
||||||
return (ZUGFeRDExporterFromA1) super.load(pdfBinary);
|
return (ZUGFeRDExporterFromA1) super.load(pdfBinary);
|
||||||
}
|
}
|
||||||
public ZUGFeRDExporterFromA1 load(InputStream pdfSource) throws IOException{
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 load(InputStream pdfSource) throws IOException{
|
||||||
return (ZUGFeRDExporterFromA1) super.load(pdfSource);
|
return (ZUGFeRDExporterFromA1) super.load(pdfSource);
|
||||||
}
|
}
|
||||||
public ZUGFeRDExporterFromA1 setCreator(String creator) {
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 setCreator(String creator) {
|
||||||
return (ZUGFeRDExporterFromA1) super.setCreator(creator);
|
return (ZUGFeRDExporterFromA1) super.setCreator(creator);
|
||||||
}
|
}
|
||||||
public ZUGFeRDExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
||||||
return (ZUGFeRDExporterFromA1) super.setConformanceLevel(newLevel);
|
return (ZUGFeRDExporterFromA1) super.setConformanceLevel(newLevel);
|
||||||
}
|
}
|
||||||
public ZUGFeRDExporterFromA1 setProducer(String producer){
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 setProducer(String producer){
|
||||||
return (ZUGFeRDExporterFromA1) super.setProducer(producer);
|
return (ZUGFeRDExporterFromA1) super.setProducer(producer);
|
||||||
}
|
}
|
||||||
public ZUGFeRDExporterFromA1 setZUGFeRDVersion(EStandard est, int version){
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 setZUGFeRDVersion(EStandard est, int version){
|
||||||
return (ZUGFeRDExporterFromA1) super.setZUGFeRDVersion(est, version);
|
return (ZUGFeRDExporterFromA1) super.setZUGFeRDVersion(est, version);
|
||||||
}
|
}
|
||||||
public ZUGFeRDExporterFromA1 setZUGFeRDVersion(int version){
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 setZUGFeRDVersion(int version){
|
||||||
return (ZUGFeRDExporterFromA1) super.setZUGFeRDVersion(version);
|
return (ZUGFeRDExporterFromA1) super.setZUGFeRDVersion(version);
|
||||||
}
|
}
|
||||||
public ZUGFeRDExporterFromA1 setXML(byte[] zugferdData) throws IOException{
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 setXML(byte[] zugferdData) throws IOException{
|
||||||
return (ZUGFeRDExporterFromA1) super.setXML(zugferdData);
|
return (ZUGFeRDExporterFromA1) super.setXML(zugferdData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZUGFeRDExporterFromA1 disableAutoClose(boolean disableAutoClose){
|
@Override
|
||||||
|
public ZUGFeRDExporterFromA1 disableAutoClose(boolean disableAutoClose){
|
||||||
return (ZUGFeRDExporterFromA1) super.disableAutoClose(disableAutoClose);
|
return (ZUGFeRDExporterFromA1) super.disableAutoClose(disableAutoClose);
|
||||||
}
|
}
|
||||||
public ZUGFeRDExporterFromA1 convertOnly() {
|
public ZUGFeRDExporterFromA1 convertOnly() {
|
||||||
|
|||||||
@@ -20,9 +20,35 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import org.apache.pdfbox.cos.*;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
|
import org.apache.pdfbox.cos.COSArray;
|
||||||
|
import org.apache.pdfbox.cos.COSBase;
|
||||||
|
import org.apache.pdfbox.cos.COSDictionary;
|
||||||
|
import org.apache.pdfbox.cos.COSName;
|
||||||
|
import org.apache.pdfbox.cos.COSObject;
|
||||||
import org.apache.pdfbox.io.IOUtils;
|
import org.apache.pdfbox.io.IOUtils;
|
||||||
import org.apache.pdfbox.pdmodel.*;
|
import org.apache.pdfbox.pdfwriter.compress.CompressParameters;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDPage;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDResources;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
||||||
@@ -33,7 +59,6 @@ import org.apache.pdfbox.pdmodel.font.PDFont;
|
|||||||
import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
|
import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
|
||||||
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
import org.apache.pdfbox.pdmodel.font.PDType0Font;
|
||||||
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
|
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
|
||||||
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
|
|
||||||
import org.apache.xmpbox.XMPMetadata;
|
import org.apache.xmpbox.XMPMetadata;
|
||||||
import org.apache.xmpbox.schema.AdobePDFSchema;
|
import org.apache.xmpbox.schema.AdobePDFSchema;
|
||||||
import org.apache.xmpbox.schema.DublinCoreSchema;
|
import org.apache.xmpbox.schema.DublinCoreSchema;
|
||||||
@@ -47,19 +72,22 @@ import org.apache.xmpbox.xml.XmpSerializer;
|
|||||||
import org.mustangproject.EStandard;
|
import org.mustangproject.EStandard;
|
||||||
import org.mustangproject.FileAttachment;
|
import org.mustangproject.FileAttachment;
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
import jakarta.activation.DataSource;
|
||||||
import javax.activation.FileDataSource;
|
import jakarta.activation.FileDataSource;
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporter, IExporter, Closeable {
|
public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporter {
|
||||||
private boolean isFacturX = true;
|
private boolean isFacturX = true;
|
||||||
|
|
||||||
public static final int DefaultZUGFeRDVersion = 2;
|
public static final int DefaultZUGFeRDVersion = 2;
|
||||||
|
protected boolean ignorePDFAErrors = false;
|
||||||
|
|
||||||
|
public ZUGFeRDExporterFromA3 ignorePDFAErrors() {
|
||||||
|
this.ignorePDFAErrors = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
||||||
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<FileAttachment>();
|
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This flag controls whether or not the metadata is overwritten, or kind of merged.
|
* This flag controls whether or not the metadata is overwritten, or kind of merged.
|
||||||
@@ -111,9 +139,6 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
|
|
||||||
protected PDDocument doc;
|
protected PDDocument doc;
|
||||||
|
|
||||||
private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
|
|
||||||
|
|
||||||
|
|
||||||
protected int ZFVersion = DefaultZUGFeRDVersion;
|
protected int ZFVersion = DefaultZUGFeRDVersion;
|
||||||
private boolean attachZUGFeRDHeaders = true;
|
private boolean attachZUGFeRDHeaders = true;
|
||||||
|
|
||||||
@@ -199,17 +224,16 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
* @return the filename of the file to be embedded
|
* @return the filename of the file to be embedded
|
||||||
*/
|
*/
|
||||||
public String getFilenameForVersion(int ver, Profile profile) {
|
public String getFilenameForVersion(int ver, Profile profile) {
|
||||||
|
if (profile.getName().equals("XRECHNUNG")) {
|
||||||
|
return "xrechnung.xml";
|
||||||
|
}
|
||||||
if (isFacturX) {
|
if (isFacturX) {
|
||||||
return "factur-x.xml";
|
return "factur-x.xml";
|
||||||
} else {
|
} else {
|
||||||
if (ver == 1) {
|
if (ver == 1) {
|
||||||
return "ZUGFeRD-invoice.xml";
|
return "ZUGFeRD-invoice.xml";
|
||||||
} else {
|
} else {
|
||||||
if (profile.getName().equals("XRECHNUNG")) {
|
return "zugferd-invoice.xml";
|
||||||
return "xrechnung.xml";
|
|
||||||
} else {
|
|
||||||
return "zugferd-invoice.xml";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,8 +244,9 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
* Generate ZF2.1 files with filename factur-x.xml
|
* Generate ZF2.1 files with filename factur-x.xml
|
||||||
*
|
*
|
||||||
* @return this (fluent setter)
|
* @return this (fluent setter)
|
||||||
* @deprecated
|
* @deprecated It's now the default anyway
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public ZUGFeRDExporterFromA3 setFacturX() {
|
public ZUGFeRDExporterFromA3 setFacturX() {
|
||||||
isFacturX = true;
|
isFacturX = true;
|
||||||
return this;
|
return this;
|
||||||
@@ -235,10 +260,9 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
*
|
*
|
||||||
* @param XRechnungVersion the XRechnung version
|
* @param XRechnungVersion the XRechnung version
|
||||||
*/
|
*/
|
||||||
public void setXRechnungSpecificVersion(String XRechnungVersion)
|
public void setXRechnungSpecificVersion(String XRechnungVersion) {
|
||||||
{
|
this.XRechnungVersion = XRechnungVersion;
|
||||||
this.XRechnungVersion = XRechnungVersion;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
@@ -258,7 +282,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
*/
|
*/
|
||||||
public ZUGFeRDExporterFromA3 load(byte[] pdfBinary) throws IOException {
|
public ZUGFeRDExporterFromA3 load(byte[] pdfBinary) throws IOException {
|
||||||
ensurePDFIsValid(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
|
ensurePDFIsValid(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
|
||||||
doc = PDDocument.load(pdfBinary);
|
doc = Loader.loadPDF(pdfBinary);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,15 +306,16 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
* @param ZUGFeRDfilename the pdf file name
|
* @param ZUGFeRDfilename the pdf file name
|
||||||
* @throws IOException if anything is wrong in the target location
|
* @throws IOException if anything is wrong in the target location
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void export(String ZUGFeRDfilename) throws IOException {
|
public void export(String ZUGFeRDfilename) throws IOException {
|
||||||
if (!documentPrepared) {
|
if (!documentPrepared) {
|
||||||
prepareDocument();
|
prepareDocument();
|
||||||
}
|
}
|
||||||
if ((!fileAttached) && (attachZUGFeRDHeaders)) {
|
if ((!fileAttached) && (attachZUGFeRDHeaders)) {
|
||||||
throw new IOException(
|
throw new IOException(
|
||||||
"File must be attached (usually with setTransaction) before perfoming this operation");
|
"File must be attached (usually with setTransaction) before perfoming this operation");
|
||||||
}
|
}
|
||||||
doc.save(ZUGFeRDfilename);
|
doc.save(ZUGFeRDfilename, CompressParameters.NO_COMPRESSION);
|
||||||
if (!disableAutoClose) {
|
if (!disableAutoClose) {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
@@ -309,15 +334,16 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
* @param output the OutputStream
|
* @param output the OutputStream
|
||||||
* @throws IOException if anything is wrong in the OutputStream
|
* @throws IOException if anything is wrong in the OutputStream
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void export(OutputStream output) throws IOException {
|
public void export(OutputStream output) throws IOException {
|
||||||
if (!documentPrepared) {
|
if (!documentPrepared) {
|
||||||
prepareDocument();
|
prepareDocument();
|
||||||
}
|
}
|
||||||
if ((!fileAttached) && (attachZUGFeRDHeaders)) {
|
if ((!fileAttached) && (attachZUGFeRDHeaders)) {
|
||||||
throw new IOException(
|
throw new IOException(
|
||||||
"File must be attached (usually with setTransaction) before perfoming this operation");
|
"File must be attached (usually with setTransaction) before perfoming this operation");
|
||||||
}
|
}
|
||||||
doc.save(output);
|
doc.save(output, CompressParameters.NO_COMPRESSION);
|
||||||
if (!disableAutoClose) {
|
if (!disableAutoClose) {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
@@ -371,7 +397,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
ef.setSize(data.length);
|
ef.setSize(data.length);
|
||||||
ef.setCreationDate(new GregorianCalendar());
|
ef.setCreationDate(new GregorianCalendar());
|
||||||
|
|
||||||
ef.setModDate(GregorianCalendar.getInstance());
|
ef.setModDate(Calendar.getInstance());
|
||||||
|
|
||||||
fs.setEmbeddedFile(ef);
|
fs.setEmbeddedFile(ef);
|
||||||
|
|
||||||
@@ -403,7 +429,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
doc.getDocumentCatalog().setNames(names);
|
doc.getDocumentCatalog().setNames(names);
|
||||||
|
|
||||||
// AF entry (Array) in catalog with the FileSpec
|
// AF entry (Array) in catalog with the FileSpec
|
||||||
COSBase AFEntry = (COSBase) doc.getDocumentCatalog().getCOSObject().getItem("AF");
|
COSBase AFEntry = doc.getDocumentCatalog().getCOSObject().getItem("AF");
|
||||||
if ((AFEntry == null)) {
|
if ((AFEntry == null)) {
|
||||||
COSArray cosArray = new COSArray();
|
COSArray cosArray = new COSArray();
|
||||||
cosArray.add(fs);
|
cosArray.add(fs);
|
||||||
@@ -413,7 +439,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
cosArray.add(fs);
|
cosArray.add(fs);
|
||||||
doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray);
|
doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray);
|
||||||
} else if ((AFEntry instanceof COSObject) &&
|
} else if ((AFEntry instanceof COSObject) &&
|
||||||
((COSObject) AFEntry).getObject() instanceof COSArray) {
|
((COSObject) AFEntry).getObject() instanceof COSArray) {
|
||||||
COSArray cosArray = (COSArray) ((COSObject) AFEntry).getObject();
|
COSArray cosArray = (COSArray) ((COSObject) AFEntry).getObject();
|
||||||
cosArray.add(fs);
|
cosArray.add(fs);
|
||||||
} else {
|
} else {
|
||||||
@@ -507,19 +533,18 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
*/
|
*/
|
||||||
protected void addXMP(XMPMetadata metadata) {
|
protected void addXMP(XMPMetadata metadata) {
|
||||||
|
|
||||||
String metaDataVersion = null; // default will be used
|
String metaDataVersion = null; // default will be used
|
||||||
|
|
||||||
// The XRechnung version may be settable from outside.
|
// The XRechnung version may be settable from outside.
|
||||||
if ((this.XRechnungVersion != null) && (this.profile != null) &&
|
if ((this.XRechnungVersion != null) && (this.profile != null) &&
|
||||||
this.profile.getName().equalsIgnoreCase(Profiles.getByName("XRECHNUNG").getName()))
|
this.profile.getName().equalsIgnoreCase(Profiles.getByName("XRECHNUNG").getName())) {
|
||||||
{
|
metaDataVersion = this.XRechnungVersion;
|
||||||
metaDataVersion = this.XRechnungVersion;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (attachZUGFeRDHeaders) {
|
if (attachZUGFeRDHeaders) {
|
||||||
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, ZFVersion, isFacturX, xmlProvider.getProfile(),
|
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, ZFVersion, isFacturX, xmlProvider.getProfile(),
|
||||||
getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion),
|
getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion),
|
||||||
getFilenameForVersion(ZFVersion, xmlProvider.getProfile()), metaDataVersion);
|
getFilenameForVersion(ZFVersion, xmlProvider.getProfile()), metaDataVersion);
|
||||||
|
|
||||||
metadata.addSchema(zf);
|
metadata.addSchema(zf);
|
||||||
}
|
}
|
||||||
@@ -529,9 +554,8 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
metadata.addSchema(pdfaex);
|
metadata.addSchema(pdfaex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeCidSet(PDDocumentCatalog catalog, PDDocument doc)
|
private void removeCidSet(PDDocument doc)
|
||||||
throws IOException
|
throws IOException {
|
||||||
{
|
|
||||||
// https://github.com/ZUGFeRD/mustangproject/issues/249
|
// https://github.com/ZUGFeRD/mustangproject/issues/249
|
||||||
|
|
||||||
COSName cidSet = COSName.getPDFName("CIDSet");
|
COSName cidSet = COSName.getPDFName("CIDSet");
|
||||||
@@ -550,6 +574,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
PDType0Font typedFont = (PDType0Font) pdFont;
|
PDType0Font typedFont = (PDType0Font) pdFont;
|
||||||
|
|
||||||
if (typedFont.getDescendantFont() instanceof PDCIDFontType2) {
|
if (typedFont.getDescendantFont() instanceof PDCIDFontType2) {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
PDCIDFontType2 f = (PDCIDFontType2) typedFont.getDescendantFont();
|
PDCIDFontType2 f = (PDCIDFontType2) typedFont.getDescendantFont();
|
||||||
PDFontDescriptor fontDescriptor = pdFont.getFontDescriptor();
|
PDFontDescriptor fontDescriptor = pdFont.getFontDescriptor();
|
||||||
|
|
||||||
@@ -571,7 +596,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
metadata = new PDMetadata(doc);
|
metadata = new PDMetadata(doc);
|
||||||
cat.setMetadata(metadata);
|
cat.setMetadata(metadata);
|
||||||
|
|
||||||
removeCidSet(cat, doc);
|
removeCidSet(doc);
|
||||||
xmp = getXmpMetadata();
|
xmp = getXmpMetadata();
|
||||||
writeAdobePDFSchema(xmp);
|
writeAdobePDFSchema(xmp);
|
||||||
writePDFAIdentificationSchema(xmp);
|
writePDFAIdentificationSchema(xmp);
|
||||||
@@ -608,6 +633,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
|
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
|
||||||
* @throws IOException if anything is wrong with already loaded PDF
|
* @throws IOException if anything is wrong with already loaded PDF
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
|
public IExporter setTransaction(IExportableTransaction trans) throws IOException {
|
||||||
this.trans = trans;
|
this.trans = trans;
|
||||||
return prepare();
|
return prepare();
|
||||||
@@ -618,22 +644,20 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
xmlProvider.generateXML(trans);
|
xmlProvider.generateXML(trans);
|
||||||
String filename = getFilenameForVersion(ZFVersion, xmlProvider.getProfile());
|
String filename = getFilenameForVersion(ZFVersion, xmlProvider.getProfile());
|
||||||
|
|
||||||
String relationship = "Alternative";
|
String relationship = "Alternative";
|
||||||
// ZUGFeRD 2.1.1 Technical Supplement | Part A | 2.2.2. Data Relationship
|
// ZUGFeRD 2.1.1 Technical Supplement | Part A | 2.2.2. Data Relationship
|
||||||
// See documentation ZUGFeRD211_EN/Documentation/ZUGFeRD-2.1.1 - Specification_TA_Part-A.pdf
|
// See documentation ZUGFeRD211_EN/Documentation/ZUGFeRD-2.1.1 - Specification_TA_Part-A.pdf
|
||||||
// https://www.ferd-net.de/standards/zugferd-2.1.1/index.html
|
// https://www.ferd-net.de/standards/zugferd-2.1.1/index.html
|
||||||
if ((this.profile != null) && (ZFVersion >= 2))
|
if ((this.profile != null) && (ZFVersion >= 2)) {
|
||||||
{
|
if (this.profile.getName().equalsIgnoreCase(Profiles.getByName("MINIMUM").getName()) ||
|
||||||
if (this.profile.getName().equalsIgnoreCase(Profiles.getByName("MINIMUM").getName()) ||
|
this.profile.getName().equalsIgnoreCase(Profiles.getByName("BASICWL").getName())) {
|
||||||
this.profile.getName().equalsIgnoreCase(Profiles.getByName("BASICWL").getName()))
|
relationship = "Data";
|
||||||
{
|
}
|
||||||
relationship = "Data";
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PDFAttachGenericFile(doc, filename, relationship,
|
PDFAttachGenericFile(doc, filename, relationship,
|
||||||
"Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)",
|
"Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)",
|
||||||
"text/xml", xmlProvider.getXML());
|
"text/xml", xmlProvider.getXML());
|
||||||
|
|
||||||
for (FileAttachment attachment : fileAttachments) {
|
for (FileAttachment attachment : fileAttachments) {
|
||||||
PDFAttachGenericFile(doc, attachment.getFilename(), attachment.getRelation(), attachment.getDescription(), attachment.getMimetype(), attachment.getData());
|
PDFAttachGenericFile(doc, attachment.getFilename(), attachment.getRelation(), attachment.getDescription(), attachment.getMimetype(), attachment.getData());
|
||||||
@@ -645,12 +669,12 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
/**
|
/**
|
||||||
* Reads the XMPMetadata from the PDDocument, if it exists.
|
* Reads the XMPMetadata from the PDDocument, if it exists.
|
||||||
* Otherwise creates XMPMetadata.
|
* Otherwise creates XMPMetadata.
|
||||||
|
*
|
||||||
* @return the finished XMPMetadata object
|
* @return the finished XMPMetadata object
|
||||||
* @throws IOException when e.g. XmpParsingException
|
* @throws IOException when e.g. XmpParsingException
|
||||||
*/
|
*/
|
||||||
protected XMPMetadata getXmpMetadata()
|
protected XMPMetadata getXmpMetadata()
|
||||||
throws IOException
|
throws IOException {
|
||||||
{
|
|
||||||
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
|
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
|
||||||
if ((meta != null) && (meta.getLength() > 0)) {
|
if ((meta != null) && (meta.getLength() > 0)) {
|
||||||
try {
|
try {
|
||||||
@@ -672,6 +696,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
/**
|
/**
|
||||||
* Sets the producer if the overwrite flag is set or the producer is not already set.
|
* Sets the producer if the overwrite flag is set or the producer is not already set.
|
||||||
* Sets the PDFVersion to 1.4 if the field is empty.
|
* Sets the PDFVersion to 1.4 if the field is empty.
|
||||||
|
*
|
||||||
* @param xmp the metadata as XML
|
* @param xmp the metadata as XML
|
||||||
*/
|
*/
|
||||||
protected void writeAdobePDFSchema(XMPMetadata xmp) {
|
protected void writeAdobePDFSchema(XMPMetadata xmp) {
|
||||||
@@ -713,13 +738,13 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected PDFAIdentificationSchema getPDFAIdentificationSchema(XMPMetadata xmp) {
|
protected PDFAIdentificationSchema getPDFAIdentificationSchema(XMPMetadata xmp) {
|
||||||
PDFAIdentificationSchema pdfaid = xmp.getPDFIdentificationSchema();
|
PDFAIdentificationSchema pdfaid = xmp.getPDFAIdentificationSchema();
|
||||||
if (pdfaid != null)
|
if (pdfaid != null)
|
||||||
if (overwrite)
|
if (overwrite)
|
||||||
xmp.removeSchema(pdfaid);
|
xmp.removeSchema(pdfaid);
|
||||||
else
|
else
|
||||||
return pdfaid;
|
return pdfaid;
|
||||||
return xmp.createAndAddPFAIdentificationSchema();
|
return xmp.createAndAddPDFAIdentificationSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void writeDublinCoreSchema(XMPMetadata xmp) {
|
protected void writeDublinCoreSchema(XMPMetadata xmp) {
|
||||||
@@ -760,7 +785,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
if (overwrite || isEmpty(xsb.getCreatorTool()) || "UnknownApplication".equals(xsb.getCreatorTool()))
|
if (overwrite || isEmpty(xsb.getCreatorTool()) || "UnknownApplication".equals(xsb.getCreatorTool()))
|
||||||
xsb.setCreatorTool(creatorTool);
|
xsb.setCreatorTool(creatorTool);
|
||||||
if (overwrite || xsb.getCreateDate() == null)
|
if (overwrite || xsb.getCreateDate() == null)
|
||||||
xsb.setCreateDate(GregorianCalendar.getInstance());
|
xsb.setCreateDate(Calendar.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected XMPBasicSchema getXmpBasicSchema(XMPMetadata xmp) {
|
protected XMPBasicSchema getXmpBasicSchema(XMPMetadata xmp) {
|
||||||
@@ -794,11 +819,11 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an OutputIntent and the sRGB color profile if no OutputIntent exist
|
* Adds an OutputIntent and the sRGB color profile if no OutputIntent exist
|
||||||
|
*
|
||||||
* @throws IOException if the ICC file cannot be read or attached to doc
|
* @throws IOException if the ICC file cannot be read or attached to doc
|
||||||
*/
|
*/
|
||||||
protected void addSRGBOutputIntend()
|
protected void addSRGBOutputIntend()
|
||||||
throws IOException
|
throws IOException {
|
||||||
{
|
|
||||||
if (!doc.getDocumentCatalog().getOutputIntents().isEmpty()) {
|
if (!doc.getDocumentCatalog().getOutputIntents().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -863,12 +888,12 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
|
|
||||||
public ZUGFeRDExporterFromA3 setZUGFeRDVersion(EStandard est, int version) {
|
public ZUGFeRDExporterFromA3 setZUGFeRDVersion(EStandard est, int version) {
|
||||||
this.ZFVersion = version;
|
this.ZFVersion = version;
|
||||||
if ((version<1) || (version>2)) {
|
if ((version < 1) || (version > 2)) {
|
||||||
throw new IllegalArgumentException("Version not supported");
|
throw new IllegalArgumentException("Version not supported");
|
||||||
}
|
}
|
||||||
int generation=version;
|
int generation = version;
|
||||||
if ((est==EStandard.facturx)&&(version==1)) {
|
if ((est == EStandard.facturx) && (version == 1)) {
|
||||||
generation=2;
|
generation = 2;
|
||||||
}
|
}
|
||||||
if (generation == 1) {
|
if (generation == 1) {
|
||||||
ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider();
|
ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider();
|
||||||
|
|||||||
@@ -20,6 +20,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
||||||
@@ -27,11 +34,11 @@ import org.apache.xmpbox.XMPMetadata;
|
|||||||
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
|
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
|
||||||
import org.apache.xmpbox.xml.DomXmpParser;
|
import org.apache.xmpbox.xml.DomXmpParser;
|
||||||
import org.apache.xmpbox.xml.XmpParsingException;
|
import org.apache.xmpbox.xml.XmpParsingException;
|
||||||
|
import org.mustangproject.FileAttachment;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
import jakarta.activation.DataSource;
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Auto-detects the source PDF-A-Version and acts accordingly
|
* Auto-detects the source PDF-A-Version and acts accordingly
|
||||||
@@ -43,16 +50,31 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
|
|||||||
|
|
||||||
protected IZUGFeRDExporter theExporter;
|
protected IZUGFeRDExporter theExporter;
|
||||||
|
|
||||||
|
protected boolean ignorePDFAErrors = false;
|
||||||
|
|
||||||
|
public ZUGFeRDExporterFromPDFA ignorePDFAErrors() {
|
||||||
|
this.ignorePDFAErrors = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
protected void determineAndSetExporter(int PDFAVersion) {
|
protected void determineAndSetExporter(int PDFAVersion) {
|
||||||
if (PDFAVersion == 3) {
|
if (PDFAVersion == 3) {
|
||||||
theExporter = new ZUGFeRDExporterFromA3();
|
theExporter = new ZUGFeRDExporterFromA3();
|
||||||
|
if (ignorePDFAErrors) {
|
||||||
|
((ZUGFeRDExporterFromA3)theExporter).ignorePDFAErrors();
|
||||||
|
}
|
||||||
} else if (PDFAVersion == 1) {
|
} else if (PDFAVersion == 1) {
|
||||||
theExporter = new ZUGFeRDExporterFromA1();
|
theExporter = new ZUGFeRDExporterFromA1();
|
||||||
|
if (ignorePDFAErrors) {
|
||||||
|
((ZUGFeRDExporterFromA1)theExporter).ignorePDFAErrors();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("PDF-A version not supported");
|
throw new IllegalArgumentException("PDF-A version not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
protected IZUGFeRDExporter getExporter() {
|
|
||||||
|
public IZUGFeRDExporter getExporter() {
|
||||||
if (theExporter==null) {
|
if (theExporter==null) {
|
||||||
throw new RuntimeException("In ZUGFeRDExporterFromPDFA, source must always be loaded before other operations are performed.");
|
throw new RuntimeException("In ZUGFeRDExporterFromPDFA, source must always be loaded before other operations are performed.");
|
||||||
}
|
}
|
||||||
@@ -79,7 +101,7 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private int getPDFAVersion(byte[] byteArrayInputStream) throws IOException {
|
private int getPDFAVersion(byte[] byteArrayInputStream) throws IOException {
|
||||||
PDDocument document = PDDocument.load(byteArrayInputStream);
|
PDDocument document = Loader.loadPDF(byteArrayInputStream);
|
||||||
PDDocumentCatalog catalog = document.getDocumentCatalog();
|
PDDocumentCatalog catalog = document.getDocumentCatalog();
|
||||||
PDMetadata metadata = catalog.getMetadata();
|
PDMetadata metadata = catalog.getMetadata();
|
||||||
// the PDF version we could get through the document but we want the PDF-A version,
|
// the PDF version we could get through the document but we want the PDF-A version,
|
||||||
@@ -89,7 +111,7 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
|
|||||||
DomXmpParser xmpParser = new DomXmpParser();
|
DomXmpParser xmpParser = new DomXmpParser();
|
||||||
XMPMetadata xmp = xmpParser.parse(metadata.createInputStream());
|
XMPMetadata xmp = xmpParser.parse(metadata.createInputStream());
|
||||||
|
|
||||||
PDFAIdentificationSchema pdfaSchema = xmp.getPDFIdentificationSchema();
|
PDFAIdentificationSchema pdfaSchema = xmp.getPDFAIdentificationSchema();
|
||||||
if (pdfaSchema != null) {
|
if (pdfaSchema != null) {
|
||||||
return pdfaSchema.getPart();
|
return pdfaSchema.getPart();
|
||||||
}
|
}
|
||||||
@@ -147,16 +169,16 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
|
|||||||
return getExporter().setCreator(creator);
|
return getExporter().setCreator(creator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZUGFeRDExporterFromPDFA setProfile(Profile p) {
|
public IZUGFeRDExporter setProfile(Profile p) {
|
||||||
return (ZUGFeRDExporterFromPDFA) getExporter().setProfile(p);
|
return getExporter().setProfile(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZUGFeRDExporterFromPDFA setProfile(String profileName) {
|
public IZUGFeRDExporter setProfile(String profileName) {
|
||||||
Profile p = Profiles.getByName(profileName);
|
Profile p = Profiles.getByName(profileName);
|
||||||
if (p==null) {
|
if (p==null) {
|
||||||
throw new RuntimeException("Profile not found.");
|
throw new RuntimeException("Profile not found.");
|
||||||
}
|
}
|
||||||
return (ZUGFeRDExporterFromPDFA) getExporter().setProfile(p);
|
return getExporter().setProfile(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IZUGFeRDExporter setConformanceLevel(PDFAConformanceLevel newLevel) {
|
public IZUGFeRDExporter setConformanceLevel(PDFAConformanceLevel newLevel) {
|
||||||
@@ -227,5 +249,14 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
|
|||||||
public void export(OutputStream output) throws IOException {
|
public void export(OutputStream output) throws IOException {
|
||||||
getExporter().export(output);
|
getExporter().export(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void attachFile(FileAttachment file) {
|
||||||
|
theExporter.attachFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attachFile(String filename, byte[] data, String mimetype, String relation) {
|
||||||
|
theExporter.attachFile(filename, data, mimetype, relation);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,53 +1,275 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import java.io.IOException;
|
import org.apache.commons.io.IOUtils;
|
||||||
import java.io.InputStream;
|
import org.apache.pdfbox.Loader;
|
||||||
import java.math.BigDecimal;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import java.math.RoundingMode;
|
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
|
||||||
import java.nio.charset.StandardCharsets;
|
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
||||||
import java.text.ParseException;
|
import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
|
||||||
import java.text.SimpleDateFormat;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
||||||
import java.util.ArrayList;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import javax.xml.xpath.XPath;
|
|
||||||
import javax.xml.xpath.XPathConstants;
|
|
||||||
import javax.xml.xpath.XPathExpression;
|
|
||||||
import javax.xml.xpath.XPathExpressionException;
|
|
||||||
import javax.xml.xpath.XPathFactory;
|
|
||||||
|
|
||||||
import org.mustangproject.*;
|
import org.mustangproject.*;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.xpath.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class ZUGFeRDInvoiceImporter {
|
||||||
|
|
||||||
public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRDInvoiceImporter.class.getCanonicalName()); // log
|
private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRDInvoiceImporter.class.getCanonicalName()); // log
|
||||||
private boolean recalcPrice = false;
|
/**
|
||||||
private boolean ignoreCalculationErrors = false;
|
* map filenames of additional XML files to their contents
|
||||||
|
*/
|
||||||
|
protected final HashMap<String, byte[]> additionalXMLs = new HashMap<>();
|
||||||
|
/**
|
||||||
|
* map filenames of all embedded files in the respective PDF
|
||||||
|
*/
|
||||||
|
protected final ArrayList<FileAttachment> PDFAttachments = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* if metadata has been found
|
||||||
|
*/
|
||||||
|
protected boolean containsMeta = false;
|
||||||
|
/**
|
||||||
|
* Raw XML form of the extracted data - may be directly obtained.
|
||||||
|
*/
|
||||||
|
protected byte[] rawXML = null;
|
||||||
|
/**
|
||||||
|
* XMP metadata
|
||||||
|
*/
|
||||||
|
protected String xmpString = null; // XMP metadata
|
||||||
|
/**
|
||||||
|
* parsed Document
|
||||||
|
*/
|
||||||
|
protected Document document;
|
||||||
|
/***
|
||||||
|
* automatically parse into importedInvoice
|
||||||
|
*/
|
||||||
|
protected boolean parseAutomatically = true;
|
||||||
|
protected Integer version;
|
||||||
|
protected CalculatedInvoice importedInvoice = null;
|
||||||
|
protected boolean recalcPrice = false;
|
||||||
|
protected boolean ignoreCalculationErrors = false;
|
||||||
|
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<>();
|
||||||
|
|
||||||
public ZUGFeRDInvoiceImporter() {
|
public ZUGFeRDInvoiceImporter() {
|
||||||
super();
|
//constructor for extending classes
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZUGFeRDInvoiceImporter(String filename) {
|
public ZUGFeRDInvoiceImporter(String pdfFilename) {
|
||||||
super(filename);
|
setPDFFilename(pdfFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZUGFeRDInvoiceImporter(InputStream stream) {
|
public ZUGFeRDInvoiceImporter(InputStream pdfStream) {
|
||||||
super(stream);
|
setInputStream(pdfStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fromXML(String XML) {
|
public void setPDFFilename(String pdfFilename) {
|
||||||
try {
|
try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) {
|
||||||
containsMeta = true;
|
extractLowLevel(bis);
|
||||||
setRawXML(XML.getBytes(StandardCharsets.UTF_8));
|
} catch (final IOException e) {
|
||||||
} catch (IOException e) {
|
LOGGER.error("Failed to extract ZUGFeRD data", e);
|
||||||
LOGGER.error(e.getMessage(), e);
|
throw new ZUGFeRDExportException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setInputStream(InputStream pdfStream) {
|
||||||
|
try {
|
||||||
|
extractLowLevel(pdfStream);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
LOGGER.error("Failed to extract ZUGFeRD data", e);
|
||||||
|
throw new ZUGFeRDExportException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* return the file names of all files embedded into the PDF
|
||||||
|
* @see for XML embedded files please use ZUGFeRDInvoiceImporter.getFileAttachmentsXML
|
||||||
|
* @return a ArrayList of FileAttachments, empty if none
|
||||||
|
*/
|
||||||
|
public List<FileAttachment> getFileAttachmentsPDF() {
|
||||||
|
return PDFAttachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts a ZUGFeRD invoice from a PDF document represented by an input stream. Errors are reported via exception handling.
|
||||||
|
*
|
||||||
|
* @param inStream a inputstream of a pdf file
|
||||||
|
*/
|
||||||
|
private void extractLowLevel(InputStream inStream) throws IOException {
|
||||||
|
BufferedInputStream pdfStream = new BufferedInputStream(inStream);
|
||||||
|
byte[] pad = new byte[4];
|
||||||
|
pdfStream.mark(0);
|
||||||
|
pdfStream.read(pad);
|
||||||
|
pdfStream.reset();
|
||||||
|
byte[] pdfSignature = {'%', 'P', 'D', 'F'};
|
||||||
|
if (Arrays.equals(pad, pdfSignature)) { // we have a pdf
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(pdfStream));
|
||||||
|
// PDDocumentInformation info = doc.getDocumentInformation();
|
||||||
|
final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
|
||||||
|
//start
|
||||||
|
|
||||||
|
if (doc.getDocumentCatalog() == null || doc.getDocumentCatalog().getMetadata() == null) {
|
||||||
|
LOGGER.info("no-xmlpart");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata();
|
||||||
|
|
||||||
|
xmpString = new String(XMLTools.getBytesFromStream(XMP), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
final PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles();
|
||||||
|
if (etn == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, PDComplexFileSpecification> efMap = etn.getNames();
|
||||||
|
// String filePath = "/tmp/";
|
||||||
|
|
||||||
|
if (efMap != null) {
|
||||||
|
extractFiles(efMap); // see
|
||||||
|
// https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/
|
||||||
|
} else {
|
||||||
|
|
||||||
|
final List<PDNameTreeNode<PDComplexFileSpecification>> kids = etn.getKids();
|
||||||
|
if (kids == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (final PDNameTreeNode<PDComplexFileSpecification> node : kids) {
|
||||||
|
final Map<String, PDComplexFileSpecification> namesL = node.getNames();
|
||||||
|
extractFiles(namesL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("Failed to parse PDF", e);
|
||||||
|
//ignore otherwise
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no PDF probably XML
|
||||||
|
containsMeta = true;
|
||||||
|
setRawXML(XMLTools.getBytesFromStream(pdfStream));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* have the item prices be determined from the line total.
|
||||||
|
* That's a workaround for some invoices which just put 0 as item price
|
||||||
|
*/
|
||||||
|
public void doRecalculateItemPricesFromLineTotals() {
|
||||||
|
recalcPrice = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* do not raise ParseExceptions even if the reproduced invoice total does not match the given value
|
||||||
|
*/
|
||||||
|
public void doIgnoreCalculationErrors() {
|
||||||
|
ignoreCalculationErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* sets th pdf attachments, and if a file is recognized (e.g. a factur-x.xml) triggers processing
|
||||||
|
* @param names the Hashmap of String, PDComplexFileSpecification
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void extractFiles(Map<String, PDComplexFileSpecification> names) throws IOException {
|
||||||
|
for (final String alias : names.keySet()) {
|
||||||
|
|
||||||
|
final PDComplexFileSpecification fileSpec = names.get(alias);
|
||||||
|
final String filename = fileSpec.getFilename();
|
||||||
|
/**
|
||||||
|
* filenames for invoice data (ZUGFeRD v1 and v2, Factur-X)
|
||||||
|
*/
|
||||||
|
|
||||||
|
final PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
|
||||||
|
if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml")) || filename.equals("xrechnung.xml") || filename.equals("order-x.xml") || filename.equals("cida.xml")) {
|
||||||
|
containsMeta = true;
|
||||||
|
|
||||||
|
// String embeddedFilename = filePath + filename;
|
||||||
|
// File file = new File(filePath + filename);
|
||||||
|
// System.out.println("Writing " + embeddedFilename);
|
||||||
|
// ByteArrayOutputStream fileBytes=new
|
||||||
|
// ByteArrayOutputStream();
|
||||||
|
// FileOutputStream fos = new FileOutputStream(file);
|
||||||
|
|
||||||
|
setRawXML(embeddedFile.toByteArray());
|
||||||
|
|
||||||
|
// fos.write(embeddedFile.getByteArray());
|
||||||
|
// fos.close();
|
||||||
|
}
|
||||||
|
if (filename.startsWith("additional_data")) {
|
||||||
|
additionalXMLs.put(filename, embeddedFile.toByteArray());
|
||||||
|
}
|
||||||
|
PDFAttachments.add(new FileAttachment(filename, embeddedFile.getSubtype(), "Data", embeddedFile.toByteArray()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* set the xml of a CII invoice
|
||||||
|
* @param rawXML the xml string
|
||||||
|
* @param doParse automatically parse input for zugferdImporter (not ZUGFeRDInvoiceImporter)
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void setRawXML(byte[] rawXML, boolean doParse) throws IOException {
|
||||||
|
this.containsMeta = true;
|
||||||
|
this.rawXML = rawXML;
|
||||||
|
this.version = null;
|
||||||
|
parseAutomatically = doParse;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setDocument();
|
||||||
|
} catch (ParserConfigurationException | SAXException e) {
|
||||||
|
LOGGER.error("Failed to parse XML", e);
|
||||||
|
throw new ZUGFeRDExportException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* set the xml of a CII invoice, simple version
|
||||||
|
* @param rawXML the cii(?) as a string
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void setRawXML(byte[] rawXML) throws IOException {
|
||||||
|
setRawXML(rawXML, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDocument() throws ParserConfigurationException, IOException, SAXException {
|
||||||
|
final DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
|
||||||
|
xmlFact.setNamespaceAware(true);
|
||||||
|
final DocumentBuilder builder = xmlFact.newDocumentBuilder();
|
||||||
|
final ByteArrayInputStream is = new ByteArrayInputStream(rawXML);
|
||||||
|
/// is.skip(guessBOMSize(is));
|
||||||
|
document = builder.parse(is);
|
||||||
|
if (parseAutomatically) {
|
||||||
|
try {
|
||||||
|
importedInvoice = new CalculatedInvoice();
|
||||||
|
extractInto(importedInvoice);
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* This will parse a XML into the given invoice object
|
* This will parse a XML into the given invoice object
|
||||||
@@ -59,6 +281,9 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseException {
|
public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseException {
|
||||||
|
|
||||||
String number = "";
|
String number = "";
|
||||||
|
String typeCode = null;
|
||||||
|
String deliveryPeriodStart = null;
|
||||||
|
String deliveryPeriodEnd = null;
|
||||||
/*
|
/*
|
||||||
* dummywerte sind derzeit noch setDueDate setIssueDate setDeliveryDate
|
* dummywerte sind derzeit noch setDueDate setIssueDate setDeliveryDate
|
||||||
* setSender setRecipient setnumber bspw. due date
|
* setSender setRecipient setnumber bspw. due date
|
||||||
@@ -68,9 +293,19 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
XPath xpath = xpathFact.newXPath();
|
XPath xpath = xpathFact.newXPath();
|
||||||
XPathExpression xpr = xpath.compile("//*[local-name()=\"SellerTradeParty\"]|//*[local-name()=\"AccountingSupplierParty\"]/*");
|
XPathExpression xpr = xpath.compile("//*[local-name()=\"SellerTradeParty\"]|//*[local-name()=\"AccountingSupplierParty\"]/*");
|
||||||
NodeList SellerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
NodeList SellerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
XPathExpression shipEx = xpath.compile("//*[local-name()=\"ShipToTradeParty\"]");
|
||||||
|
NodeList deliveryNodes = (NodeList) shipEx.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
if (deliveryNodes != null) {
|
||||||
|
zpp.setDeliveryAddress(new TradeParty(deliveryNodes));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
xpr = xpath.compile("//*[local-name()=\"BuyerTradeParty\"]|//*[local-name()=\"AccountingCustomerParty\"]/*");
|
xpr = xpath.compile("//*[local-name()=\"BuyerTradeParty\"]|//*[local-name()=\"AccountingCustomerParty\"]/*");
|
||||||
NodeList BuyerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
NodeList BuyerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
|
||||||
|
xpr = xpath.compile("//*[local-name()=\"PayeeTradeParty\"]|//*[local-name()=\"PayeeParty\"]/*");
|
||||||
|
NodeList payeeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
|
||||||
xpr = xpath.compile("//*[local-name()=\"ExchangedDocument\"]|//*[local-name()=\"HeaderExchangedDocument\"]");
|
xpr = xpath.compile("//*[local-name()=\"ExchangedDocument\"]|//*[local-name()=\"HeaderExchangedDocument\"]");
|
||||||
NodeList ExchangedDocumentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
NodeList ExchangedDocumentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
|
||||||
@@ -78,32 +313,42 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
BigDecimal expectedGrandTotal = null;
|
BigDecimal expectedGrandTotal = null;
|
||||||
NodeList totalNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
NodeList totalNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
if (totalNodes.getLength() > 0) {
|
if (totalNodes.getLength() > 0) {
|
||||||
expectedGrandTotal = new BigDecimal(totalNodes.item(0).getTextContent());
|
expectedGrandTotal = new BigDecimal(XMLTools.trimOrNull(totalNodes.item(0)));
|
||||||
|
if (zpp instanceof CalculatedInvoice) {
|
||||||
|
// usually we would re-calculate the invoice to get expectedGrandTotal
|
||||||
|
// however, for "minimal" invoices or other invoices without lines
|
||||||
|
// this will not work
|
||||||
|
((CalculatedInvoice) zpp).setGrandTotal(expectedGrandTotal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xpr = xpath.compile("//*[local-name()=\"PrepaidAmount\"]");
|
||||||
|
NodeList prepaidNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
if (prepaidNodes.getLength() > 0) {
|
||||||
|
zpp.setTotalPrepaidAmount(new BigDecimal(XMLTools.trimOrNull(prepaidNodes.item(0))));
|
||||||
}
|
}
|
||||||
|
|
||||||
Date issueDate = null;
|
Date issueDate = null;
|
||||||
Date dueDate = null;
|
Date dueDate = null;
|
||||||
Date deliveryDate = null;
|
Date deliveryDate = null;
|
||||||
|
String despatchAdviceReferencedDocument = null;
|
||||||
for (int i = 0; i < ExchangedDocumentNodes.getLength(); i++) {
|
for (int i = 0; i < ExchangedDocumentNodes.getLength(); i++) {
|
||||||
|
|
||||||
// nodes.item(i).getTextContent())) {
|
|
||||||
Node exchangedDocumentNode = ExchangedDocumentNodes.item(i);
|
Node exchangedDocumentNode = ExchangedDocumentNodes.item(i);
|
||||||
NodeList exchangedDocumentChilds = exchangedDocumentNode.getChildNodes();
|
NodeList exchangedDocumentChilds = exchangedDocumentNode.getChildNodes();
|
||||||
for (int documentChildIndex = 0; documentChildIndex < exchangedDocumentChilds
|
for (int documentChildIndex = 0; documentChildIndex < exchangedDocumentChilds.getLength(); documentChildIndex++) {
|
||||||
.getLength(); documentChildIndex++) {
|
|
||||||
Node item = exchangedDocumentChilds.item(documentChildIndex);
|
Node item = exchangedDocumentChilds.item(documentChildIndex);
|
||||||
if ((item.getLocalName() != null) && (item.getLocalName().equals("ID"))) {
|
if ((item.getLocalName() != null) && (item.getLocalName().equals("ID"))) {
|
||||||
number = item.getTextContent();
|
number = XMLTools.trimOrNull(item);
|
||||||
|
}
|
||||||
|
if ((item.getLocalName() != null) && (item.getLocalName().equals("TypeCode"))) {
|
||||||
|
typeCode = XMLTools.trimOrNull(item);
|
||||||
}
|
}
|
||||||
if ((item.getLocalName() != null) && (item.getLocalName().equals("IssueDateTime"))) {
|
if ((item.getLocalName() != null) && (item.getLocalName().equals("IssueDateTime"))) {
|
||||||
NodeList issueDateTimeChilds = item.getChildNodes();
|
NodeList issueDateTimeChilds = item.getChildNodes();
|
||||||
for (int issueDateChildIndex = 0; issueDateChildIndex < issueDateTimeChilds
|
for (int issueDateChildIndex = 0; issueDateChildIndex < issueDateTimeChilds.getLength(); issueDateChildIndex++) {
|
||||||
.getLength(); issueDateChildIndex++) {
|
|
||||||
if ((issueDateTimeChilds.item(issueDateChildIndex).getLocalName() != null)
|
if ((issueDateTimeChilds.item(issueDateChildIndex).getLocalName() != null)
|
||||||
&& (issueDateTimeChilds.item(issueDateChildIndex).getLocalName()
|
&& (issueDateTimeChilds.item(issueDateChildIndex).getLocalName().equals("DateTimeString"))) {
|
||||||
.equals("DateTimeString"))) {
|
issueDate = new SimpleDateFormat("yyyyMMdd").parse(XMLTools.trimOrNull(issueDateTimeChilds.item(issueDateChildIndex)));
|
||||||
issueDate = new SimpleDateFormat("yyyyMMdd")
|
|
||||||
.parse(issueDateTimeChilds.item(issueDateChildIndex).getTextContent());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,50 +358,49 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
if (rootNode.equals("Invoice")) {
|
if (rootNode.equals("Invoice")) {
|
||||||
// UBL...
|
// UBL...
|
||||||
number = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"ID\"]").trim();
|
number = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"ID\"]").trim();
|
||||||
issueDate = new SimpleDateFormat("yyyy-MM-dd")
|
issueDate = new SimpleDateFormat("yyyy-MM-dd").parse(extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"IssueDate\"]").trim());
|
||||||
.parse(extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"IssueDate\"]").trim());
|
|
||||||
String dueDt = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"DueDate\"]").trim();
|
String dueDt = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"DueDate\"]").trim();
|
||||||
if (dueDt.length() > 0) {
|
if (dueDt.length() > 0) {
|
||||||
dueDate = new SimpleDateFormat("yyyy-MM-dd")
|
dueDate = new SimpleDateFormat("yyyy-MM-dd").parse(dueDt);
|
||||||
.parse(dueDt);
|
|
||||||
}
|
}
|
||||||
String deliveryDt = extractString("//*[local-name()=\"Delivery\"]/*[local-name()=\"ActualDeliveryDate\"]").trim();
|
String deliveryDt = extractString("//*[local-name()=\"Delivery\"]/*[local-name()=\"ActualDeliveryDate\"]").trim();
|
||||||
if (deliveryDt.length() > 0) {
|
if (deliveryDt.length() > 0) {
|
||||||
deliveryDate = new SimpleDateFormat("yyyy-MM-dd")
|
deliveryDate = new SimpleDateFormat("yyyy-MM-dd").parse(deliveryDt);
|
||||||
.parse(deliveryDt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeDelivery\"]");
|
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeDelivery\"]");
|
||||||
NodeList headerTradeDeliveryNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
NodeList headerTradeDeliveryNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
|
||||||
for (int i = 0; i < headerTradeDeliveryNodes.getLength(); i++) {
|
for (int i = 0; i < headerTradeDeliveryNodes.getLength(); i++) {
|
||||||
// nodes.item(i).getTextContent())) {
|
|
||||||
Node headerTradeDeliveryNode = headerTradeDeliveryNodes.item(i);
|
Node headerTradeDeliveryNode = headerTradeDeliveryNodes.item(i);
|
||||||
NodeList headerTradeDeliveryChilds = headerTradeDeliveryNode.getChildNodes();
|
NodeList headerTradeDeliveryChilds = headerTradeDeliveryNode.getChildNodes();
|
||||||
for (int deliveryChildIndex = 0; deliveryChildIndex < headerTradeDeliveryChilds
|
for (int deliveryChildIndex = 0; deliveryChildIndex < headerTradeDeliveryChilds.getLength(); deliveryChildIndex++) {
|
||||||
.getLength(); deliveryChildIndex++) {
|
if (headerTradeDeliveryChilds.item(deliveryChildIndex).getLocalName() != null) {
|
||||||
if ((headerTradeDeliveryChilds.item(deliveryChildIndex).getLocalName() != null)
|
if (headerTradeDeliveryChilds.item(deliveryChildIndex).getLocalName().equals("ActualDeliverySupplyChainEvent")) {
|
||||||
&& (headerTradeDeliveryChilds.item(deliveryChildIndex).getLocalName()
|
NodeList actualDeliveryChilds = headerTradeDeliveryChilds.item(deliveryChildIndex).getChildNodes();
|
||||||
.equals("ActualDeliverySupplyChainEvent"))) {
|
for (int actualDeliveryChildIndex = 0; actualDeliveryChildIndex < actualDeliveryChilds.getLength(); actualDeliveryChildIndex++) {
|
||||||
NodeList actualDeliveryChilds = headerTradeDeliveryChilds.item(deliveryChildIndex).getChildNodes();
|
if ((actualDeliveryChilds.item(actualDeliveryChildIndex).getLocalName() != null)
|
||||||
for (int actualDeliveryChildIndex = 0; actualDeliveryChildIndex < actualDeliveryChilds
|
&& (actualDeliveryChilds.item(actualDeliveryChildIndex).getLocalName().equals("OccurrenceDateTime"))) {
|
||||||
.getLength(); actualDeliveryChildIndex++) {
|
NodeList occurenceChilds = actualDeliveryChilds.item(actualDeliveryChildIndex).getChildNodes();
|
||||||
if ((actualDeliveryChilds.item(actualDeliveryChildIndex).getLocalName() != null)
|
for (int occurenceChildIndex = 0; occurenceChildIndex < occurenceChilds.getLength(); occurenceChildIndex++) {
|
||||||
&& (actualDeliveryChilds.item(actualDeliveryChildIndex).getLocalName()
|
if ((occurenceChilds.item(occurenceChildIndex).getLocalName() != null)
|
||||||
.equals("OccurrenceDateTime"))) {
|
&& (occurenceChilds.item(occurenceChildIndex).getLocalName().equals("DateTimeString"))) {
|
||||||
NodeList occurenceChilds = actualDeliveryChilds.item(actualDeliveryChildIndex)
|
deliveryDate = new SimpleDateFormat("yyyyMMdd").parse(XMLTools.trimOrNull(occurenceChilds.item(occurenceChildIndex)));
|
||||||
.getChildNodes();
|
}
|
||||||
for (int occurenceChildIndex = 0; occurenceChildIndex < occurenceChilds
|
|
||||||
.getLength(); occurenceChildIndex++) {
|
|
||||||
if ((occurenceChilds.item(occurenceChildIndex).getLocalName() != null)
|
|
||||||
&& (occurenceChilds.item(occurenceChildIndex).getLocalName()
|
|
||||||
.equals("DateTimeString"))) {
|
|
||||||
deliveryDate = new SimpleDateFormat("yyyyMMdd")
|
|
||||||
.parse(occurenceChilds.item(occurenceChildIndex).getTextContent());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (headerTradeDeliveryChilds.item(deliveryChildIndex).getLocalName().equals("DespatchAdviceReferencedDocument")) {
|
||||||
|
NodeList despatchAdviceChilds = headerTradeDeliveryChilds.item(deliveryChildIndex).getChildNodes();
|
||||||
|
for (int despatchAdviceChildIndex = 0; despatchAdviceChildIndex < despatchAdviceChilds.getLength(); despatchAdviceChildIndex++) {
|
||||||
|
if (despatchAdviceChilds.item(despatchAdviceChildIndex).getLocalName() != null
|
||||||
|
&& despatchAdviceChilds.item(despatchAdviceChildIndex).getLocalName().equals("IssuerAssignedID")) {
|
||||||
|
despatchAdviceReferencedDocument = XMLTools.trimOrNull(despatchAdviceChilds.item(despatchAdviceChildIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,34 +410,28 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
String buyerOrderIssuerAssignedID = null;
|
String buyerOrderIssuerAssignedID = null;
|
||||||
String sellerOrderIssuerAssignedID = null;
|
String sellerOrderIssuerAssignedID = null;
|
||||||
for (int i = 0; i < headerTradeAgreementNodes.getLength(); i++) {
|
for (int i = 0; i < headerTradeAgreementNodes.getLength(); i++) {
|
||||||
// nodes.item(i).getTextContent())) {
|
// XMLTools.trimOrNull(nodes.item(i)))) {
|
||||||
Node headerTradeAgreementNode = headerTradeAgreementNodes.item(i);
|
Node headerTradeAgreementNode = headerTradeAgreementNodes.item(i);
|
||||||
NodeList headerTradeAgreementChilds = headerTradeAgreementNode.getChildNodes();
|
NodeList headerTradeAgreementChilds = headerTradeAgreementNode.getChildNodes();
|
||||||
for (int agreementChildIndex = 0; agreementChildIndex < headerTradeAgreementChilds
|
for (int agreementChildIndex = 0; agreementChildIndex < headerTradeAgreementChilds.getLength(); agreementChildIndex++) {
|
||||||
.getLength(); agreementChildIndex++) {
|
if (headerTradeAgreementChilds.item(agreementChildIndex).getLocalName() != null) {
|
||||||
if ((headerTradeAgreementChilds.item(agreementChildIndex).getLocalName() != null)
|
if (headerTradeAgreementChilds.item(agreementChildIndex).getLocalName().equals("BuyerOrderReferencedDocument")) {
|
||||||
&& (headerTradeAgreementChilds.item(agreementChildIndex).getLocalName()
|
NodeList buyerOrderChilds = headerTradeAgreementChilds.item(agreementChildIndex).getChildNodes();
|
||||||
.equals("BuyerOrderReferencedDocument"))) {
|
for (int buyerOrderChildIndex = 0; buyerOrderChildIndex < buyerOrderChilds.getLength(); buyerOrderChildIndex++) {
|
||||||
NodeList buyerOrderChilds = headerTradeAgreementChilds.item(agreementChildIndex).getChildNodes();
|
if ((buyerOrderChilds.item(buyerOrderChildIndex).getLocalName() != null)
|
||||||
for (int buyerOrderChildIndex = 0; buyerOrderChildIndex < buyerOrderChilds
|
&& (buyerOrderChilds.item(buyerOrderChildIndex).getLocalName().equals("IssuerAssignedID"))) {
|
||||||
.getLength(); buyerOrderChildIndex++) {
|
buyerOrderIssuerAssignedID = XMLTools.trimOrNull(buyerOrderChilds.item(buyerOrderChildIndex));
|
||||||
if ((buyerOrderChilds.item(buyerOrderChildIndex).getLocalName() != null)
|
}
|
||||||
&& (buyerOrderChilds.item(buyerOrderChildIndex).getLocalName()
|
|
||||||
.equals("IssuerAssignedID"))) {
|
|
||||||
buyerOrderIssuerAssignedID = buyerOrderChilds.item(buyerOrderChildIndex).getTextContent();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if ((headerTradeAgreementChilds.item(agreementChildIndex).getLocalName() != null)
|
if (headerTradeAgreementChilds.item(agreementChildIndex).getLocalName().equals("SellerOrderReferencedDocument")) {
|
||||||
&& (headerTradeAgreementChilds.item(agreementChildIndex).getLocalName()
|
NodeList sellerOrderChilds = headerTradeAgreementChilds.item(agreementChildIndex).getChildNodes();
|
||||||
.equals("SellerOrderReferencedDocument"))) {
|
for (int sellerOrderChildIndex = 0; sellerOrderChildIndex < sellerOrderChilds.getLength(); sellerOrderChildIndex++) {
|
||||||
NodeList sellerOrderChilds = headerTradeAgreementChilds.item(agreementChildIndex).getChildNodes();
|
if ((sellerOrderChilds.item(sellerOrderChildIndex).getLocalName() != null)
|
||||||
for (int sellerOrderChildIndex = 0; sellerOrderChildIndex < sellerOrderChilds
|
&& (sellerOrderChilds.item(sellerOrderChildIndex).getLocalName().equals("IssuerAssignedID"))) {
|
||||||
.getLength(); sellerOrderChildIndex++) {
|
sellerOrderIssuerAssignedID = XMLTools.trimOrNull(sellerOrderChilds.item(sellerOrderChildIndex));
|
||||||
if ((sellerOrderChilds.item(sellerOrderChildIndex).getLocalName() != null)
|
}
|
||||||
&& (sellerOrderChilds.item(sellerOrderChildIndex).getLocalName()
|
|
||||||
.equals("IssuerAssignedID"))) {
|
|
||||||
sellerOrderIssuerAssignedID = sellerOrderChilds.item(sellerOrderChildIndex).getTextContent();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,63 +439,90 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String currency = extractString("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"InvoiceCurrencyCode\"]|*[local-name()=\"DocumentCurrencyCode\"]");
|
||||||
|
zpp.setCurrency(currency);
|
||||||
|
|
||||||
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]|//*[local-name()=\"ApplicableSupplyChainTradeSettlement\"]");
|
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]|//*[local-name()=\"ApplicableSupplyChainTradeSettlement\"]");
|
||||||
NodeList headerTradeSettlementNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
NodeList headerTradeSettlementNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
List<BankDetails> bankDetails = new ArrayList<>();
|
||||||
|
String directDebitMandateID = null;
|
||||||
String IBAN = null, BIC = null;
|
String IBAN = null, BIC = null;
|
||||||
|
|
||||||
for (int i = 0; i < headerTradeSettlementNodes.getLength(); i++) {
|
for (int i = 0; i < headerTradeSettlementNodes.getLength(); i++) {
|
||||||
// nodes.item(i).getTextContent())) {
|
// XMLTools.trimOrNull(nodes.item(i)))) {
|
||||||
Node headerTradeSettlementNode = headerTradeSettlementNodes.item(i);
|
Node headerTradeSettlementNode = headerTradeSettlementNodes.item(i);
|
||||||
|
|
||||||
NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes();
|
NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes();
|
||||||
for (int settlementChildIndex = 0; settlementChildIndex < headerTradeSettlementChilds
|
for (int settlementChildIndex = 0; settlementChildIndex < headerTradeSettlementChilds.getLength(); settlementChildIndex++) {
|
||||||
.getLength(); settlementChildIndex++) {
|
|
||||||
if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
|
if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
|
||||||
&& (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName()
|
&& (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("SpecifiedTradePaymentTerms"))) {
|
||||||
.equals("SpecifiedTradePaymentTerms"))) {
|
|
||||||
NodeList paymentTermChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes();
|
NodeList paymentTermChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes();
|
||||||
for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds
|
for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds.getLength(); paymentTermChildIndex++) {
|
||||||
.getLength(); paymentTermChildIndex++) {
|
if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("DueDateDateTime"))) {
|
||||||
if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds
|
|
||||||
.item(paymentTermChildIndex).getLocalName().equals("DueDateDateTime"))) {
|
|
||||||
NodeList dueDateChilds = paymentTermChilds.item(paymentTermChildIndex).getChildNodes();
|
NodeList dueDateChilds = paymentTermChilds.item(paymentTermChildIndex).getChildNodes();
|
||||||
for (int dueDateChildIndex = 0; dueDateChildIndex < dueDateChilds
|
for (int dueDateChildIndex = 0; dueDateChildIndex < dueDateChilds.getLength(); dueDateChildIndex++) {
|
||||||
.getLength(); dueDateChildIndex++) {
|
if ((dueDateChilds.item(dueDateChildIndex).getLocalName() != null) && (dueDateChilds.item(dueDateChildIndex).getLocalName().equals("DateTimeString"))) {
|
||||||
if ((dueDateChilds.item(dueDateChildIndex).getLocalName() != null) && (dueDateChilds
|
dueDate = new SimpleDateFormat("yyyyMMdd").parse(XMLTools.trimOrNull(dueDateChilds.item(dueDateChildIndex)));
|
||||||
.item(dueDateChildIndex).getLocalName().equals("DateTimeString"))) {
|
|
||||||
dueDate = new SimpleDateFormat("yyyyMMdd")
|
|
||||||
.parse(dueDateChilds.item(dueDateChildIndex).getTextContent());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("DirectDebitMandateID"))) {
|
||||||
|
directDebitMandateID = paymentTermChilds.item(paymentTermChildIndex).getTextContent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
|
if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
|
||||||
&& (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName()
|
&& (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("SpecifiedTradeSettlementPaymentMeans"))) {
|
||||||
.equals("SpecifiedTradeSettlementPaymentMeans"))) {
|
|
||||||
NodeList paymentMeansChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes();
|
NodeList paymentMeansChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes();
|
||||||
for (int paymentMeansChildIndex = 0; paymentMeansChildIndex < paymentMeansChilds
|
IBAN = null;
|
||||||
.getLength(); paymentMeansChildIndex++) {
|
BIC = null;
|
||||||
if ((paymentMeansChilds.item(paymentMeansChildIndex).getLocalName() != null) && (paymentMeansChilds
|
for (int paymentMeansChildIndex = 0; paymentMeansChildIndex < paymentMeansChilds.getLength(); paymentMeansChildIndex++) {
|
||||||
.item(paymentMeansChildIndex).getLocalName().equals("PayeePartyCreditorFinancialAccount"))) {
|
|
||||||
|
if ((paymentMeansChilds.item(paymentMeansChildIndex).getLocalName() != null) && (paymentMeansChilds.item(paymentMeansChildIndex).getLocalName().equals("PayeePartyCreditorFinancialAccount") || paymentMeansChilds.item(paymentMeansChildIndex).getLocalName().equals("PayerPartyDebtorFinancialAccount"))) {
|
||||||
NodeList accountChilds = paymentMeansChilds.item(paymentMeansChildIndex).getChildNodes();
|
NodeList accountChilds = paymentMeansChilds.item(paymentMeansChildIndex).getChildNodes();
|
||||||
for (int accountChildIndex = 0; accountChildIndex < accountChilds
|
for (int accountChildIndex = 0; accountChildIndex < accountChilds.getLength(); accountChildIndex++) {
|
||||||
.getLength(); accountChildIndex++) {
|
if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds.item(accountChildIndex).getLocalName().equals("IBANID"))) {//CII
|
||||||
if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds
|
IBAN = XMLTools.trimOrNull(accountChilds.item(accountChildIndex));
|
||||||
.item(accountChildIndex).getLocalName().equals("IBANID"))) {//CII
|
|
||||||
IBAN = accountChilds.item(accountChildIndex).getTextContent();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((paymentMeansChilds.item(paymentMeansChildIndex).getLocalName() != null) && (paymentMeansChilds
|
if ((paymentMeansChilds.item(paymentMeansChildIndex).getLocalName() != null) && (paymentMeansChilds.item(paymentMeansChildIndex).getLocalName().equals("PayeeSpecifiedCreditorFinancialInstitution"))) {
|
||||||
.item(paymentMeansChildIndex).getLocalName().equals("PayeePartyCreditorFinancialInstitution"))) {
|
|
||||||
NodeList accountChilds = paymentMeansChilds.item(paymentMeansChildIndex).getChildNodes();
|
NodeList accountChilds = paymentMeansChilds.item(paymentMeansChildIndex).getChildNodes();
|
||||||
for (int accountChildIndex = 0; accountChildIndex < accountChilds
|
for (int accountChildIndex = 0; accountChildIndex < accountChilds.getLength(); accountChildIndex++) {
|
||||||
.getLength(); accountChildIndex++) {
|
if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds.item(accountChildIndex).getLocalName().equals("BICID"))) {//CII
|
||||||
if ((accountChilds.item(accountChildIndex).getLocalName() != null) && (accountChilds
|
BIC = XMLTools.trimOrNull(accountChilds.item(accountChildIndex));
|
||||||
.item(accountChildIndex).getLocalName().equals("BICID"))) {//CII
|
}
|
||||||
BIC = accountChilds.item(accountChildIndex).getTextContent();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (IBAN != null) {
|
||||||
|
BankDetails bd = new BankDetails(IBAN);
|
||||||
|
if (BIC != null) {
|
||||||
|
bd.setBIC(BIC);
|
||||||
|
}
|
||||||
|
bankDetails.add(bd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
|
||||||
|
&& (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("BillingSpecifiedPeriod"))) {
|
||||||
|
NodeList periodChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes();
|
||||||
|
for (int periodChildIndex = 0; periodChildIndex < periodChilds.getLength(); periodChildIndex++) {
|
||||||
|
if ((periodChilds.item(periodChildIndex).getLocalName() != null) && (periodChilds.item(periodChildIndex).getLocalName().equals("StartDateTime"))) {
|
||||||
|
|
||||||
|
NodeList startPeriodChilds = periodChilds.item(periodChildIndex).getChildNodes();
|
||||||
|
for (int startPeriodIndex = 0; startPeriodIndex < startPeriodChilds.getLength(); startPeriodIndex++) {
|
||||||
|
if ((startPeriodChilds.item(startPeriodIndex).getLocalName() != null) && (startPeriodChilds.item(startPeriodIndex).getLocalName().equals("DateTimeString"))) {//CII
|
||||||
|
deliveryPeriodStart = XMLTools.trimOrNull(startPeriodChilds.item(startPeriodIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((periodChilds.item(periodChildIndex).getLocalName() != null) && (periodChilds.item(periodChildIndex).getLocalName().equals("EndDateTime"))) {
|
||||||
|
NodeList endPeriodChilds = periodChilds.item(periodChildIndex).getChildNodes();
|
||||||
|
for (int endPeriodIndex = 0; endPeriodIndex < endPeriodChilds.getLength(); endPeriodIndex++) {
|
||||||
|
if ((endPeriodChilds.item(endPeriodIndex).getLocalName() != null) && (endPeriodChilds.item(endPeriodIndex).getLocalName().equals("DateTimeString"))) {//CII
|
||||||
|
deliveryPeriodEnd = XMLTools.trimOrNull(endPeriodChilds.item(endPeriodIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,39 +531,47 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((deliveryPeriodStart != null) && (deliveryPeriodEnd != null)) {
|
||||||
|
zpp.setDetailedDeliveryPeriod(XMLTools.tryDate(deliveryPeriodStart), XMLTools.tryDate(deliveryPeriodEnd));
|
||||||
|
} else if (deliveryPeriodStart != null) {
|
||||||
|
zpp.setDeliveryDate(XMLTools.tryDate(deliveryPeriodStart));
|
||||||
|
}
|
||||||
|
|
||||||
xpr = xpath.compile("//*[local-name()=\"PaymentMeans\"]"); //UBL only
|
xpr = xpath.compile("//*[local-name()=\"PaymentMeans\"]"); //UBL only
|
||||||
NodeList paymentMeansNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
NodeList paymentMeansNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
|
||||||
for (int i = 0; i < paymentMeansNodes.getLength(); i++) {
|
for (int i = 0; i < paymentMeansNodes.getLength(); i++) {
|
||||||
// nodes.item(i).getTextContent())) {
|
// XMLTools.trimOrNull(nodes.item(i)))) {
|
||||||
Node paymentMeansNode = paymentMeansNodes.item(i);
|
Node paymentMeansNode = paymentMeansNodes.item(i);
|
||||||
NodeList paymentMeansChilds = paymentMeansNode.getChildNodes();
|
NodeList paymentMeansChilds = paymentMeansNode.getChildNodes();
|
||||||
for (int meansChildIndex = 0; meansChildIndex < paymentMeansChilds
|
for (int meansChildIndex = 0; meansChildIndex < paymentMeansChilds.getLength(); meansChildIndex++) {
|
||||||
.getLength(); meansChildIndex++) {
|
|
||||||
if ((paymentMeansChilds.item(meansChildIndex).getLocalName() != null)
|
if ((paymentMeansChilds.item(meansChildIndex).getLocalName() != null)
|
||||||
&& (paymentMeansChilds.item(meansChildIndex).getLocalName()
|
&& (paymentMeansChilds.item(meansChildIndex).getLocalName().equals("PayeeFinancialAccount"))) {
|
||||||
.equals("PayeeFinancialAccount"))) {
|
|
||||||
NodeList paymentTermChilds = paymentMeansChilds.item(meansChildIndex).getChildNodes();
|
NodeList paymentTermChilds = paymentMeansChilds.item(meansChildIndex).getChildNodes();
|
||||||
for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds
|
for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds.getLength(); paymentTermChildIndex++) {
|
||||||
.getLength(); paymentTermChildIndex++) {
|
if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("ID"))) {
|
||||||
if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds
|
IBAN = XMLTools.trimOrNull(paymentTermChilds.item(paymentTermChildIndex));
|
||||||
.item(paymentTermChildIndex).getLocalName().equals("ID"))) {
|
if (IBAN != null) {
|
||||||
IBAN = paymentTermChilds.item(paymentTermChildIndex).getTextContent();
|
BankDetails bd = new BankDetails(IBAN);
|
||||||
|
bankDetails.add(bd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zpp.setDueDate(dueDate).setDeliveryDate(deliveryDate).setIssueDate(issueDate)
|
zpp.setDueDate(dueDate).setDeliveryDate(deliveryDate).setIssueDate(issueDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentCode(typeCode);
|
||||||
.setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number);
|
|
||||||
if (IBAN != null) {
|
if ((directDebitMandateID != null) && (IBAN != null)) {
|
||||||
BankDetails bd = new BankDetails(IBAN);
|
DirectDebit d = new DirectDebit(IBAN, directDebitMandateID);
|
||||||
if (BIC != null) {
|
zpp.getSender().addDebitDetails(d);
|
||||||
bd.setBIC(BIC);
|
}
|
||||||
}
|
|
||||||
zpp.getSender().addBankDetails(bd);
|
bankDetails.forEach(bankDetail -> zpp.getSender().addBankDetails(bankDetail));
|
||||||
|
|
||||||
|
if (payeeNodes.getLength() > 0) {
|
||||||
|
zpp.setPayee(new TradeParty(payeeNodes));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buyerOrderIssuerAssignedID != null) {
|
if (buyerOrderIssuerAssignedID != null) {
|
||||||
@@ -307,15 +580,17 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
if (sellerOrderIssuerAssignedID != null) {
|
if (sellerOrderIssuerAssignedID != null) {
|
||||||
zpp.setSellerOrderReferencedDocumentID(sellerOrderIssuerAssignedID);
|
zpp.setSellerOrderReferencedDocumentID(sellerOrderIssuerAssignedID);
|
||||||
}
|
}
|
||||||
|
if (despatchAdviceReferencedDocument != null) {
|
||||||
|
zpp.setDespatchAdviceReferencedDocumentID(despatchAdviceReferencedDocument);
|
||||||
|
}
|
||||||
|
|
||||||
//.addItem(new Item(new Product("Testprodukt","","C62",BigDecimal.ZERO),amount,new BigDecimal(1.0)))
|
|
||||||
zpp.setOwnOrganisationName(extractString("//*[local-name()=\"SellerTradeParty\"]/*[local-name()=\"Name\"]|//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyName\"]").trim());
|
zpp.setOwnOrganisationName(extractString("//*[local-name()=\"SellerTradeParty\"]/*[local-name()=\"Name\"]|//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyName\"]").trim());
|
||||||
|
|
||||||
xpr = xpath.compile("//*[local-name()=\"BuyerReference\"]");
|
xpr = xpath.compile("//*[local-name()=\"BuyerReference\"]");
|
||||||
String buyerReference = null;
|
String buyerReference = null;
|
||||||
totalNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
prepaidNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
if (totalNodes.getLength() > 0) {
|
if (prepaidNodes.getLength() > 0) {
|
||||||
buyerReference = totalNodes.item(0).getTextContent();
|
buyerReference = XMLTools.trimOrNull(prepaidNodes.item(0));
|
||||||
}
|
}
|
||||||
if (buyerReference != null) {
|
if (buyerReference != null) {
|
||||||
zpp.setReferenceNumber(buyerReference);
|
zpp.setReferenceNumber(buyerReference);
|
||||||
@@ -333,6 +608,16 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// now handling base64 encoded attachments AttachmentBinaryObject=CII, EmbeddedDocumentBinaryObject=UBL
|
||||||
|
xpr = xpath.compile("//*[local-name()=\"AttachmentBinaryObject\"]|//*[local-name()=\"EmbeddedDocumentBinaryObject\"]");
|
||||||
|
NodeList attachmentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
|
||||||
|
for (int i = 0; i < attachmentNodes.getLength(); i++) {
|
||||||
|
FileAttachment fa = new FileAttachment(attachmentNodes.item(i).getAttributes().getNamedItem("filename").getNodeValue(), attachmentNodes.item(i).getAttributes().getNamedItem("mimeCode").getNodeValue(), "Data", Base64.getDecoder().decode(XMLTools.trimOrNull(attachmentNodes.item(i))));
|
||||||
|
fileAttachments.add(fa);
|
||||||
|
// filename = "Aufmass.png" mimeCode = "image/png"
|
||||||
|
//EmbeddedDocumentBinaryObject cbc:EmbeddedDocumentBinaryObject mimeCode="image/png" filename="Aufmass.png"
|
||||||
|
}
|
||||||
|
|
||||||
// item level charges+allowances are not yet handled but a lower item price will
|
// item level charges+allowances are not yet handled but a lower item price will
|
||||||
// be read,
|
// be read,
|
||||||
// so the invoice remains arithmetically correct
|
// so the invoice remains arithmetically correct
|
||||||
@@ -344,6 +629,7 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
boolean isCharge = true;
|
boolean isCharge = true;
|
||||||
String chargeAmount = null;
|
String chargeAmount = null;
|
||||||
String reason = null;
|
String reason = null;
|
||||||
|
String reasonCode = null;
|
||||||
String taxPercent = null;
|
String taxPercent = null;
|
||||||
for (int chargeChildIndex = 0; chargeChildIndex < chargeNodeChilds.getLength(); chargeChildIndex++) {
|
for (int chargeChildIndex = 0; chargeChildIndex < chargeNodeChilds.getLength(); chargeChildIndex++) {
|
||||||
String chargeChildName = chargeNodeChilds.item(chargeChildIndex).getLocalName();
|
String chargeChildName = chargeNodeChilds.item(chargeChildIndex).getLocalName();
|
||||||
@@ -351,26 +637,24 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
|
|
||||||
if (chargeChildName.equals("ChargeIndicator")) {
|
if (chargeChildName.equals("ChargeIndicator")) {
|
||||||
NodeList indicatorChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes();
|
NodeList indicatorChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes();
|
||||||
for (int indicatorChildIndex = 0; indicatorChildIndex < indicatorChilds
|
for (int indicatorChildIndex = 0; indicatorChildIndex < indicatorChilds.getLength(); indicatorChildIndex++) {
|
||||||
.getLength(); indicatorChildIndex++) {
|
|
||||||
if ((indicatorChilds.item(indicatorChildIndex).getLocalName() != null)
|
if ((indicatorChilds.item(indicatorChildIndex).getLocalName() != null)
|
||||||
&& (indicatorChilds.item(indicatorChildIndex).getLocalName()
|
&& (indicatorChilds.item(indicatorChildIndex).getLocalName().equals("Indicator"))) {
|
||||||
.equals("Indicator"))) {
|
isCharge = XMLTools.trimOrNull(indicatorChilds.item(indicatorChildIndex)).equalsIgnoreCase("true");
|
||||||
isCharge = indicatorChilds.item(indicatorChildIndex).getTextContent()
|
|
||||||
.equalsIgnoreCase("true");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (chargeChildName.equals("ActualAmount")) {
|
} else if (chargeChildName.equals("ActualAmount")) {
|
||||||
chargeAmount = chargeNodeChilds.item(chargeChildIndex).getTextContent();
|
chargeAmount = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
|
||||||
} else if (chargeChildName.equals("Reason")) {
|
} else if (chargeChildName.equals("Reason")) {
|
||||||
reason = chargeNodeChilds.item(chargeChildIndex).getTextContent();
|
reason = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
|
||||||
|
} else if (chargeChildName.equals("ReasonCode")) {
|
||||||
|
reasonCode = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
|
||||||
} else if (chargeChildName.equals("CategoryTradeTax")) {
|
} else if (chargeChildName.equals("CategoryTradeTax")) {
|
||||||
NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes();
|
NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes();
|
||||||
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
|
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
|
||||||
String taxItemName = taxChilds.item(taxChildIndex).getLocalName();
|
String taxItemName = taxChilds.item(taxChildIndex).getLocalName();
|
||||||
if ((taxItemName != null) && (taxItemName.equals("RateApplicablePercent")
|
if ((taxItemName != null) && (taxItemName.equals("RateApplicablePercent") || taxItemName.equals("ApplicablePercent"))) {
|
||||||
|| taxItemName.equals("ApplicablePercent"))) {
|
taxPercent = XMLTools.trimOrNull(taxChilds.item(taxChildIndex));
|
||||||
taxPercent = taxChilds.item(taxChildIndex).getTextContent();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -382,16 +666,21 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
if (reason != null) {
|
if (reason != null) {
|
||||||
c.setReason(reason);
|
c.setReason(reason);
|
||||||
}
|
}
|
||||||
|
if (reasonCode != null) {
|
||||||
|
c.setReasonCode(reasonCode);
|
||||||
|
}
|
||||||
if (taxPercent != null) {
|
if (taxPercent != null) {
|
||||||
c.setTaxPercent(new BigDecimal(taxPercent));
|
c.setTaxPercent(new BigDecimal(taxPercent));
|
||||||
}
|
}
|
||||||
|
|
||||||
zpp.addCharge(c);
|
zpp.addCharge(c);
|
||||||
} else {
|
} else {
|
||||||
Allowance a = new Allowance(new BigDecimal(chargeAmount));
|
Allowance a = new Allowance(new BigDecimal(chargeAmount));
|
||||||
if (reason != null) {
|
if (reason != null) {
|
||||||
a.setReason(reason);
|
a.setReason(reason);
|
||||||
}
|
}
|
||||||
|
if (reasonCode != null) {
|
||||||
|
a.setReasonCode(reasonCode);
|
||||||
|
}
|
||||||
if (taxPercent != null) {
|
if (taxPercent != null) {
|
||||||
a.setTaxPercent(new BigDecimal(taxPercent));
|
a.setTaxPercent(new BigDecimal(taxPercent));
|
||||||
}
|
}
|
||||||
@@ -401,7 +690,8 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TransactionCalculator tc = new TransactionCalculator(zpp);
|
TransactionCalculator tc = new TransactionCalculator(zpp);
|
||||||
String expectedStringTotalGross = tc.getGrandTotal().toPlainString();
|
String expectedStringTotalGross = tc.getGrandTotal()
|
||||||
|
.subtract(Objects.requireNonNullElse(zpp.getTotalPrepaidAmount(), BigDecimal.ZERO)).toPlainString();
|
||||||
EStandard whichType;
|
EStandard whichType;
|
||||||
try {
|
try {
|
||||||
whichType = getStandard();
|
whichType = getStandard();
|
||||||
@@ -414,13 +704,95 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
&& ((!expectedStringTotalGross.equals(XMLTools.nDigitFormat(expectedGrandTotal, 2)))
|
&& ((!expectedStringTotalGross.equals(XMLTools.nDigitFormat(expectedGrandTotal, 2)))
|
||||||
&& (!ignoreCalculationErrors))) {
|
&& (!ignoreCalculationErrors))) {
|
||||||
throw new ParseException(
|
throw new ParseException(
|
||||||
"Could not reproduce the invoice, this could mean that it could not be read properly", 0);
|
"Could not reproduce the invoice, this could mean that it could not be read properly exp "+expectedStringTotalGross+" is "+XMLTools.nDigitFormat(expectedGrandTotal, 2), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return zpp;
|
return zpp;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Document getDocument() {
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String extractString(String xpathStr) {
|
||||||
|
if (!containsMeta) {
|
||||||
|
throw new ZUGFeRDExportException("No suitable data/ZUGFeRD file could be found.");
|
||||||
|
}
|
||||||
|
final String result;
|
||||||
|
try {
|
||||||
|
final Document document = getDocument();
|
||||||
|
final XPathFactory xpathFact = XPathFactory.newInstance();
|
||||||
|
final XPath xpath = xpathFact.newXPath();
|
||||||
|
result = xpath.evaluate(xpathStr, document);
|
||||||
|
} catch (final XPathExpressionException e) {
|
||||||
|
LOGGER.error("Failed to evaluate XPath", e);
|
||||||
|
throw new ZUGFeRDExportException(e);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EStandard getStandard() throws Exception {
|
||||||
|
if (!containsMeta) {
|
||||||
|
throw new Exception("Not yet parsed");
|
||||||
|
}
|
||||||
|
final String head = getUTF8();
|
||||||
|
String rootNode = extractString("local-name(/*)");
|
||||||
|
if (rootNode.equals("CrossIndustryDocument")) {
|
||||||
|
return EStandard.zugferd;
|
||||||
|
} else if (rootNode.equals("Invoice")) {
|
||||||
|
return EStandard.ubl;
|
||||||
|
} else if (rootNode.equals("CreditNote")) {
|
||||||
|
return EStandard.ubl;
|
||||||
|
} else if (rootNode.equals("CrossIndustryInvoice")) {
|
||||||
|
return EStandard.facturx;
|
||||||
|
} else if (rootNode.equals("SCRDMCCBDACIDAMessageStructure")) {
|
||||||
|
return EStandard.despatchadvice;
|
||||||
|
} else if (head.contains("<rsm:SCRDMCCBDACIOMessageStructure")) {
|
||||||
|
return EStandard.orderx;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("ZUGFeRD version could not be determined");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return return UTF8 XML (without BOM) of the invoice
|
||||||
|
*/
|
||||||
|
public String getUTF8() {
|
||||||
|
if (rawXML == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (rawXML.length < 3) {
|
||||||
|
return new String(rawXML);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final byte[] bomlessData;
|
||||||
|
|
||||||
|
if ((rawXML[0] == (byte) 0xEF)
|
||||||
|
&& (rawXML[1] == (byte) 0xBB)
|
||||||
|
&& (rawXML[2] == (byte) 0xBF)) {
|
||||||
|
// I don't like BOMs, lets remove it
|
||||||
|
bomlessData = new byte[rawXML.length - 3];
|
||||||
|
System.arraycopy(rawXML, 3, bomlessData, 0,
|
||||||
|
rawXML.length - 3);
|
||||||
|
} else {
|
||||||
|
bomlessData = rawXML;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new String(bomlessData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
*
|
||||||
|
* @return the file attachments embedded in XML (using base64) decoded as byte array,
|
||||||
|
* for PDF embedded files in FX use getFileAttachmentsPDF()
|
||||||
|
*/
|
||||||
|
public List<FileAttachment> getFileAttachmentsXML() {
|
||||||
|
return fileAttachments;
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* This will parse a XML into a invoice object
|
* This will parse a XML into a invoice object
|
||||||
*
|
*
|
||||||
@@ -435,18 +807,18 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
|
||||||
* have the item prices be determined from the line total.
|
|
||||||
* That's a workaround for some invoices which just put 0 as item price
|
|
||||||
*/
|
|
||||||
public void doRecalculateItemPricesFromLineTotals() {
|
|
||||||
recalcPrice = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* do not raise ParseExceptions even if the reproduced invoice total does not match the given value
|
* sets the XML for the importer to parse
|
||||||
|
* @param XML the UBL or CII
|
||||||
*/
|
*/
|
||||||
public void doIgnoreCalculationErrors() {
|
public void fromXML(String XML) {
|
||||||
ignoreCalculationErrors = true;
|
try {
|
||||||
|
containsMeta = true;
|
||||||
|
setRawXML(XML.getBytes(StandardCharsets.UTF_8));
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,28 +20,57 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import org.apache.fop.apps.*;
|
import java.io.BufferedOutputStream;
|
||||||
import org.apache.fop.configuration.Configuration;
|
import java.io.ByteArrayInputStream;
|
||||||
import org.apache.fop.configuration.ConfigurationException;
|
import java.io.ByteArrayOutputStream;
|
||||||
import org.apache.fop.configuration.DefaultConfigurationBuilder;
|
import java.io.File;
|
||||||
import org.apache.xmlgraphics.util.MimeConstants;
|
import java.io.FileInputStream;
|
||||||
import org.mustangproject.CII.CIIToUBL;
|
import java.io.FileNotFoundException;
|
||||||
import org.mustangproject.ClasspathResolverURIAdapter;
|
import java.io.FileOutputStream;
|
||||||
import org.xml.sax.SAXException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PipedInputStream;
|
||||||
|
import java.io.PipedOutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
import javax.xml.transform.*;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.transform.Result;
|
||||||
|
import javax.xml.transform.Source;
|
||||||
|
import javax.xml.transform.Templates;
|
||||||
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerConfigurationException;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
import javax.xml.transform.TransformerFactory;
|
||||||
|
import javax.xml.transform.URIResolver;
|
||||||
import javax.xml.transform.sax.SAXResult;
|
import javax.xml.transform.sax.SAXResult;
|
||||||
import javax.xml.transform.stream.StreamResult;
|
import javax.xml.transform.stream.StreamResult;
|
||||||
import javax.xml.transform.stream.StreamSource;
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
|
||||||
import java.io.*;
|
import org.apache.fop.apps.FOPException;
|
||||||
import java.net.URI;
|
import org.apache.fop.apps.FOUserAgent;
|
||||||
import java.net.URISyntaxException;
|
import org.apache.fop.apps.Fop;
|
||||||
import java.nio.charset.StandardCharsets;
|
import org.apache.fop.apps.FopFactory;
|
||||||
import java.nio.file.Files;
|
import org.apache.fop.apps.FopFactoryBuilder;
|
||||||
import java.nio.file.Paths;
|
import org.apache.fop.apps.io.ResourceResolverFactory;
|
||||||
import java.util.logging.Level;
|
import org.apache.fop.configuration.Configuration;
|
||||||
import java.util.logging.Logger;
|
import org.apache.fop.configuration.ConfigurationException;
|
||||||
|
import org.apache.fop.configuration.DefaultConfigurationBuilder;
|
||||||
|
import org.apache.xmlgraphics.util.MimeConstants;
|
||||||
|
import org.mustangproject.ClasspathResolverURIAdapter;
|
||||||
|
import org.mustangproject.EStandard;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.helger.commons.io.stream.StreamHelper;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
public class ZUGFeRDVisualizer {
|
public class ZUGFeRDVisualizer {
|
||||||
|
|
||||||
@@ -53,7 +82,7 @@ public class ZUGFeRDVisualizer {
|
|||||||
|
|
||||||
static final ClassLoader CLASS_LOADER = ZUGFeRDVisualizer.class.getClassLoader();
|
static final ClassLoader CLASS_LOADER = ZUGFeRDVisualizer.class.getClassLoader();
|
||||||
private static final String RESOURCE_PATH = "";
|
private static final String RESOURCE_PATH = "";
|
||||||
private static final Logger LOG = Logger.getLogger(ZUGFeRDVisualizer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRDVisualizer.class);
|
||||||
// private static File createTempFileResult(final Transformer transformer, final
|
// private static File createTempFileResult(final Transformer transformer, final
|
||||||
// StreamSource toTransform,
|
// StreamSource toTransform,
|
||||||
// final String suffix) throws TransformerException, IOException {
|
// final String suffix) throws TransformerException, IOException {
|
||||||
@@ -68,6 +97,7 @@ public class ZUGFeRDVisualizer {
|
|||||||
private TransformerFactory mFactory = null;
|
private TransformerFactory mFactory = null;
|
||||||
private Templates mXsltXRTemplate = null;
|
private Templates mXsltXRTemplate = null;
|
||||||
private Templates mXsltUBLTemplate = null;
|
private Templates mXsltUBLTemplate = null;
|
||||||
|
private Templates mXsltCIOTemplate = null;
|
||||||
private Templates mXsltHTMLTemplate = null;
|
private Templates mXsltHTMLTemplate = null;
|
||||||
private Templates mXsltPDFTemplate = null;
|
private Templates mXsltPDFTemplate = null;
|
||||||
private Templates mXsltZF1HTMLTemplate = null;
|
private Templates mXsltZF1HTMLTemplate = null;
|
||||||
@@ -78,28 +108,60 @@ public class ZUGFeRDVisualizer {
|
|||||||
mFactory.setURIResolver(new ClasspathResourceURIResolver());
|
mFactory.setURIResolver(new ClasspathResourceURIResolver());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* returns which standard is used, CII or UBL
|
||||||
|
* @param fis inputstream (will be consumed)
|
||||||
|
* @return (facturx = cii)
|
||||||
|
*/
|
||||||
|
public EStandard findOutStandardFromRootNode(InputStream fis) {
|
||||||
|
|
||||||
|
String zf1Signature = "CrossIndustryDocument";
|
||||||
|
String zf2Signature = "CrossIndustryInvoice";
|
||||||
|
String ublSignature = "Invoice";
|
||||||
|
String ublCreditNoteSignature = "CreditNote";
|
||||||
|
String cioSignature = "SCRDMCCBDACIOMessageStructure";
|
||||||
|
|
||||||
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||||
|
dbf.setNamespaceAware(true);
|
||||||
|
try {
|
||||||
|
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||||
|
Document doc = db.parse(new InputSource(fis));
|
||||||
|
Element root = doc.getDocumentElement();
|
||||||
|
if (root.getLocalName().equals(zf1Signature)) {
|
||||||
|
return EStandard.zugferd;
|
||||||
|
} else if (root.getLocalName().equals(zf2Signature)) {
|
||||||
|
return EStandard.facturx;
|
||||||
|
} else if (root.getLocalName().equals(ublSignature)) {
|
||||||
|
return EStandard.ubl;
|
||||||
|
} else if (root.getLocalName().equals(ublCreditNoteSignature)) {
|
||||||
|
return EStandard.ubl_creditnote;
|
||||||
|
} else if (root.getLocalName().equals(cioSignature)) {
|
||||||
|
return EStandard.orderx;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("Failed to recognize standard", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public String visualize(String xmlFilename, Language lang)
|
public String visualize(String xmlFilename, Language lang)
|
||||||
throws FileNotFoundException, TransformerException, UnsupportedEncodingException {
|
throws FileNotFoundException, TransformerException, IOException, SAXException, ParserConfigurationException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (mXsltXRTemplate == null) {
|
|
||||||
mXsltXRTemplate = mFactory.newTemplates(
|
|
||||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
|
|
||||||
}
|
|
||||||
if (mXsltPDFTemplate == null) {
|
if (mXsltPDFTemplate == null) {
|
||||||
mXsltPDFTemplate = mFactory.newTemplates(
|
mXsltPDFTemplate = mFactory.newTemplates(
|
||||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl")));
|
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl")));
|
||||||
}
|
}
|
||||||
if (mXsltHTMLTemplate == null) {
|
if (mXsltHTMLTemplate == null) {
|
||||||
mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource(
|
mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource(
|
||||||
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html." + lang.name().toLowerCase() + ".xsl")));
|
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html." + lang.name().toLowerCase() + ".xsl")));
|
||||||
}
|
}
|
||||||
if (mXsltZF1HTMLTemplate == null) {
|
if (mXsltZF1HTMLTemplate == null) {
|
||||||
mXsltZF1HTMLTemplate = mFactory.newTemplates(new StreamSource(
|
mXsltZF1HTMLTemplate = mFactory.newTemplates(new StreamSource(
|
||||||
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt")));
|
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt")));
|
||||||
}
|
}
|
||||||
} catch (TransformerConfigurationException ex) {
|
} catch (TransformerConfigurationException ex) {
|
||||||
LOG.log(Level.SEVERE, null, ex);
|
LOGGER.error("Failed to init XSLT templates", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,35 +175,39 @@ public class ZUGFeRDVisualizer {
|
|||||||
try {
|
try {
|
||||||
fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename)), StandardCharsets.UTF_8);
|
fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename)), StandardCharsets.UTF_8);
|
||||||
} catch (IOException e2) {
|
} catch (IOException e2) {
|
||||||
LOG.log(Level.SEVERE, null, e2);
|
LOGGER.error("Failed to read file content", e2);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
|
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
String zf1Signature = "rsm:CrossIndustryDocument";
|
|
||||||
String zf2Signature = "rsm:CrossIndustryInvoice";
|
|
||||||
String ublSignature = "ubl:Invoice";
|
|
||||||
String ublCreditNoteSignature = "ubl:CreditNote";
|
|
||||||
boolean doPostProcessing = false;
|
boolean doPostProcessing = false;
|
||||||
if (fileContent.contains(zf1Signature)) {
|
|
||||||
|
|
||||||
|
fis = new FileInputStream(xmlFilename); // fis wont reset() so re-read from beginning
|
||||||
|
EStandard thestandard = findOutStandardFromRootNode(fis);
|
||||||
|
fis = new FileInputStream(xmlFilename); // fis wont reset() so re-read from beginning
|
||||||
|
|
||||||
|
if (thestandard == EStandard.zugferd) {
|
||||||
applyZF1XSLT(fis, baos);
|
applyZF1XSLT(fis, baos);
|
||||||
|
} else if (thestandard == EStandard.facturx) {
|
||||||
} else if (fileContent.contains(zf2Signature)) {
|
|
||||||
|
|
||||||
//zf2 or fx
|
//zf2 or fx
|
||||||
applyZF2XSLT(fis, iaos);
|
applyZF2XSLT(fis, iaos);
|
||||||
doPostProcessing = true;
|
doPostProcessing = true;
|
||||||
} else if (fileContent.contains(ublSignature)) {
|
} else if (thestandard == EStandard.ubl) {
|
||||||
//zf2 or fx
|
//zf2 or fx
|
||||||
applyUBL2XSLT(fis, iaos);
|
applyUBL2XSLT(fis, iaos);
|
||||||
doPostProcessing = true;
|
doPostProcessing = true;
|
||||||
|
} else if (thestandard == EStandard.ubl_creditnote) {
|
||||||
} else if (fileContent.contains(ublCreditNoteSignature)) {
|
|
||||||
//zf2 or fx
|
//zf2 or fx
|
||||||
applyUBLCreditNote2XSLT(fis, iaos);
|
applyUBLCreditNote2XSLT(fis, iaos);
|
||||||
doPostProcessing = true;
|
doPostProcessing = true;
|
||||||
|
} else if (thestandard == EStandard.orderx) {
|
||||||
|
//zf2 or fx
|
||||||
|
applyCIO2XSLT(fis, iaos);
|
||||||
|
doPostProcessing = true;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("File does not look like CII or UBL");
|
||||||
}
|
}
|
||||||
if (doPostProcessing) {
|
if (doPostProcessing) {
|
||||||
// take the copy of the stream and re-write it to an InputStream
|
// take the copy of the stream and re-write it to an InputStream
|
||||||
@@ -158,61 +224,52 @@ public class ZUGFeRDVisualizer {
|
|||||||
// ByteArrayOutputStream
|
// ByteArrayOutputStream
|
||||||
iaos.writeTo(out);
|
iaos.writeTo(out);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.log(Level.SEVERE, null, e);
|
LOGGER.error("Failed to write to stream", e);
|
||||||
} finally {
|
} finally {
|
||||||
// close the PipedOutputStream here because we're done writing data
|
// close the PipedOutputStream here because we're done writing data
|
||||||
// once this thread has completed its run
|
// once this thread has completed its run
|
||||||
if (out != null) {
|
StreamHelper.close(out);
|
||||||
// close the PipedOutputStream cleanly
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
LOG.log(Level.SEVERE, null, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
applyXSLTToHTML(in, baos);
|
applyXSLTToHTML(in, baos);
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
LOG.log(Level.SEVERE, null, e1);
|
LOGGER.error("Failed to create HTML", e1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return baos.toString("UTF-8");
|
return baos.toString(StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String toFOP(String xmlFilename)
|
protected String toFOP(String xmlFilename)
|
||||||
throws FileNotFoundException, TransformerException, UnsupportedEncodingException {
|
throws FileNotFoundException, TransformerException {
|
||||||
|
|
||||||
try {
|
|
||||||
if (mXsltXRTemplate == null) {
|
|
||||||
mXsltXRTemplate = mFactory.newTemplates(
|
|
||||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
|
|
||||||
}
|
|
||||||
if (mXsltPDFTemplate == null) {
|
|
||||||
mXsltPDFTemplate = mFactory.newTemplates(
|
|
||||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl")));
|
|
||||||
}
|
|
||||||
} catch (TransformerConfigurationException ex) {
|
|
||||||
LOG.log(Level.SEVERE, null, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
FileInputStream fis = new FileInputStream(xmlFilename);
|
FileInputStream fis = new FileInputStream(xmlFilename);
|
||||||
String fileContent = "";
|
EStandard theStandard = findOutStandardFromRootNode(fis);
|
||||||
|
fis = new FileInputStream(xmlFilename);//rewind :-(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename)), StandardCharsets.UTF_8);
|
if (mXsltPDFTemplate == null) {
|
||||||
} catch (IOException e2) {
|
mXsltPDFTemplate = mFactory.newTemplates(
|
||||||
LOG.log(Level.SEVERE, null, e2);
|
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl")));
|
||||||
|
}
|
||||||
|
} catch (TransformerConfigurationException ex) {
|
||||||
|
LOGGER.error("Failed to init XSLT templates", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
|
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
//zf2 or fx
|
//zf2 or fx
|
||||||
applyZF2XSLT(fis, iaos);
|
if (theStandard == EStandard.facturx) {
|
||||||
|
applyZF2XSLT(fis, iaos);
|
||||||
|
} else if (theStandard == EStandard.ubl) {
|
||||||
|
applyUBL2XSLT(fis, iaos);
|
||||||
|
} else if (theStandard == EStandard.ubl_creditnote) {
|
||||||
|
applyUBLCreditNote2XSLT(fis, iaos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PipedInputStream in = new PipedInputStream();
|
PipedInputStream in = new PipedInputStream();
|
||||||
PipedOutputStream out;
|
PipedOutputStream out;
|
||||||
@@ -227,68 +284,38 @@ public class ZUGFeRDVisualizer {
|
|||||||
// ByteArrayOutputStream
|
// ByteArrayOutputStream
|
||||||
iaos.writeTo(out);
|
iaos.writeTo(out);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.log(Level.SEVERE, null, e);
|
LOGGER.error("Failed to write to stream", e);
|
||||||
} finally {
|
} finally {
|
||||||
// close the PipedOutputStream here because we're done writing data
|
// close the PipedOutputStream here because we're done writing data
|
||||||
// once this thread has completed its run
|
// once this thread has completed its run
|
||||||
if (out != null) {
|
StreamHelper.close(out);
|
||||||
// close the PipedOutputStream cleanly
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
LOG.log(Level.SEVERE, null, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
applyXSLTToPDF(in, baos);
|
applyXSLTToPDF(in, baos);
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
LOG.log(Level.SEVERE, null, e1);
|
LOGGER.error("Failed to create PDF", e1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return baos.toString("UTF-8");
|
return baos.toString(StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toPDF(String xmlFilename, String pdfFilename) {
|
public void toPDF(String xmlFilename, String pdfFilename) {
|
||||||
|
|
||||||
// the writing part
|
// the writing part
|
||||||
CIIToUBL c2u = new CIIToUBL();
|
File XMLinputFile = new File(xmlFilename);
|
||||||
String sourceFilename = "factur-x.xml";
|
|
||||||
File CIIinputFile = new File(xmlFilename);
|
|
||||||
|
|
||||||
String expected = null;
|
|
||||||
String result = null;
|
String result = null;
|
||||||
|
|
||||||
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
|
|
||||||
/* remove file endings so that tests can also pass after checking
|
/* remove file endings so that tests can also pass after checking
|
||||||
out from git with arbitrary options (which may include CSRF changes)
|
out from git with arbitrary options (which may include CSRF changes)
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
result = zvi.toFOP(CIIinputFile.getAbsolutePath());
|
result = this.toFOP(XMLinputFile.getAbsolutePath());
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException | TransformerException e) {
|
||||||
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
|
LOGGER.error("Failed to apply FOP", e);
|
||||||
} catch (TransformerException e) {
|
|
||||||
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
|
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
FopConfParser parser = null;
|
|
||||||
try {
|
|
||||||
//parsing configuration
|
|
||||||
parser = new FopConfParser(CLASS_LOADER.getResourceAsStream("fop-config.xconf"), new URI("file:///"));
|
|
||||||
|
|
||||||
} catch (SAXException e) {
|
|
||||||
throw new UncheckedIOException(new IOException(e));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException(e);
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
|
|
||||||
}*/
|
|
||||||
// FopFactoryBuilder builder = parser.getFopFactoryBuilder();
|
|
||||||
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
|
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
|
||||||
|
|
||||||
Configuration cfg = null;
|
Configuration cfg = null;
|
||||||
@@ -304,9 +331,14 @@ public class ZUGFeRDVisualizer {
|
|||||||
|
|
||||||
FopFactory fopFactory = builder.build();//FopFactory.newInstance(new File("c:\\Users\\jstaerk\\temp\\fop-config.xconf"));
|
FopFactory fopFactory = builder.build();//FopFactory.newInstance(new File("c:\\Users\\jstaerk\\temp\\fop-config.xconf"));
|
||||||
|
|
||||||
|
fopFactory.getFontManager().setResourceResolver(
|
||||||
|
ResourceResolverFactory.createInternalResourceResolver(
|
||||||
|
new File(".").toURI(),
|
||||||
|
new ClasspathResolverURIAdapter()));
|
||||||
|
|
||||||
FOUserAgent userAgent = fopFactory.newFOUserAgent();
|
FOUserAgent userAgent = fopFactory.newFOUserAgent();
|
||||||
|
|
||||||
userAgent.getRendererOptions().put("pdf-a-mode", "PDF/A-1b");
|
userAgent.getRendererOptions().put("pdf-a-mode", "PDF/A-3b");
|
||||||
|
|
||||||
// Step 2: Set up output stream.
|
// Step 2: Set up output stream.
|
||||||
// Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams).
|
// Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams).
|
||||||
@@ -330,33 +362,39 @@ public class ZUGFeRDVisualizer {
|
|||||||
// Step 6: Start XSLT transformation and FOP processing
|
// Step 6: Start XSLT transformation and FOP processing
|
||||||
transformer.transform(src, res);
|
transformer.transform(src, res);
|
||||||
|
|
||||||
//Files.write(Paths.get("C:\\Users\\jstaerk\\temp\\fop.pdf"), res.toString().getBytes(StandardCharsets.UTF_8));
|
} catch (FOPException | IOException | TransformerException e) {
|
||||||
|
LOGGER.error("Failed to create PDF", e);
|
||||||
} catch (FOPException e) {
|
|
||||||
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
|
|
||||||
} catch (TransformerConfigurationException e) {
|
|
||||||
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
|
|
||||||
} catch (TransformerException e) {
|
|
||||||
Logger.getLogger(ZUGFeRDVisualizer.class.getName()).log(Level.SEVERE, null, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void applyZF2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
protected void applyZF2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||||
throws TransformerException {
|
throws TransformerException {
|
||||||
|
if (mXsltXRTemplate == null) {
|
||||||
|
mXsltXRTemplate = mFactory.newTemplates(
|
||||||
|
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
|
||||||
|
|
||||||
|
}
|
||||||
Transformer transformer = mXsltXRTemplate.newTransformer();
|
Transformer transformer = mXsltXRTemplate.newTransformer();
|
||||||
|
|
||||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void applyCIO2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||||
|
throws TransformerException {
|
||||||
|
if (mXsltCIOTemplate == null) {
|
||||||
|
mXsltCIOTemplate = mFactory.newTemplates(
|
||||||
|
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cio-xr.xsl")));
|
||||||
|
}
|
||||||
|
Transformer transformer = mXsltCIOTemplate.newTransformer();
|
||||||
|
|
||||||
|
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||||
|
}
|
||||||
|
|
||||||
protected void applyUBL2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
protected void applyUBL2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||||
throws TransformerException {
|
throws TransformerException {
|
||||||
if (mXsltUBLTemplate == null) {
|
if (mXsltUBLTemplate == null) {
|
||||||
mXsltUBLTemplate = mFactory.newTemplates(
|
mXsltUBLTemplate = mFactory.newTemplates(
|
||||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ubl-invoice-xr.xsl")));
|
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ubl-invoice-xr.xsl")));
|
||||||
}
|
}
|
||||||
Transformer transformer = mXsltUBLTemplate.newTransformer();
|
Transformer transformer = mXsltUBLTemplate.newTransformer();
|
||||||
|
|
||||||
@@ -364,10 +402,10 @@ public class ZUGFeRDVisualizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void applyUBLCreditNote2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
protected void applyUBLCreditNote2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||||
throws TransformerException {
|
throws TransformerException {
|
||||||
if (mXsltUBLTemplate == null) {
|
if (mXsltUBLTemplate == null) {
|
||||||
mXsltUBLTemplate = mFactory.newTemplates(
|
mXsltUBLTemplate = mFactory.newTemplates(
|
||||||
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ubl-creditnote-xr.xsl")));
|
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ubl-creditnote-xr.xsl")));
|
||||||
}
|
}
|
||||||
Transformer transformer = mXsltUBLTemplate.newTransformer();
|
Transformer transformer = mXsltUBLTemplate.newTransformer();
|
||||||
|
|
||||||
@@ -375,21 +413,21 @@ public class ZUGFeRDVisualizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void applyZF1XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
protected void applyZF1XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||||
throws TransformerException {
|
throws TransformerException {
|
||||||
Transformer transformer = mXsltZF1HTMLTemplate.newTransformer();
|
Transformer transformer = mXsltZF1HTMLTemplate.newTransformer();
|
||||||
|
|
||||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void applyXSLTToHTML(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
protected void applyXSLTToHTML(final InputStream xmlFile, final OutputStream HTMLOutstream)
|
||||||
throws TransformerException {
|
throws TransformerException {
|
||||||
Transformer transformer = mXsltHTMLTemplate.newTransformer();
|
Transformer transformer = mXsltHTMLTemplate.newTransformer();
|
||||||
|
|
||||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void applyXSLTToPDF(final InputStream xmlFile, final OutputStream PDFOutstream)
|
protected void applyXSLTToPDF(final InputStream xmlFile, final OutputStream PDFOutstream)
|
||||||
throws TransformerException {
|
throws TransformerException {
|
||||||
Transformer transformer = mXsltPDFTemplate.newTransformer();
|
Transformer transformer = mXsltPDFTemplate.newTransformer();
|
||||||
|
|
||||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(PDFOutstream));
|
transformer.transform(new StreamSource(xmlFile), new StreamResult(PDFOutstream));
|
||||||
|
|||||||
@@ -30,5 +30,5 @@ public class TaxCategoryCodeTypeConstants {
|
|||||||
public static final String UNTAXEDSERVICE = "O";
|
public static final String UNTAXEDSERVICE = "O";
|
||||||
public static final String INTRACOMMUNITY = "K";
|
public static final String INTRACOMMUNITY = "K";
|
||||||
|
|
||||||
public static Set<String> CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE).collect(Collectors.toSet());
|
public static Set<String> CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package org.mustangproject.util;
|
||||||
|
|
||||||
|
public final class ByteArraySearcher {
|
||||||
|
|
||||||
|
private ByteArraySearcher() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int indexOf(byte[] haystack, byte[] needle) {
|
||||||
|
if (needle.length > haystack.length) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any needle to search?
|
||||||
|
if (needle.length == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= haystack.length - needle.length; i++) {
|
||||||
|
boolean found = true;
|
||||||
|
for (int j = 0; j < needle.length; j++) {
|
||||||
|
if (haystack[i + j] != needle[j]) {
|
||||||
|
found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean contains(byte[] haystack, byte[] needle) {
|
||||||
|
return indexOf(haystack, needle) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean startsWith(byte[] haystack, byte[] needle) {
|
||||||
|
if (needle.length > haystack.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any needle to search?
|
||||||
|
if (needle.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < needle.length; j++) {
|
||||||
|
if (haystack[j] != needle[j]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
144
library/src/main/java/org/mustangproject/util/NodeMap.java
Normal file
144
library/src/main/java/org/mustangproject/util/NodeMap.java
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* *********************************************************************
|
||||||
|
* <p>
|
||||||
|
* Copyright (c) 2024 Jan N. Klug
|
||||||
|
* <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.util;
|
||||||
|
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link NodeMap} contains a {@link Map} representation of DOM object
|
||||||
|
* It can be constructed either from the children of a single {@link Node} or a {@link NodeList}.
|
||||||
|
*/
|
||||||
|
public class NodeMap {
|
||||||
|
private final Map<String, List<Node>> map = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link NodeMap}
|
||||||
|
* The {@link Node} that is passed to the constructor must not be null.
|
||||||
|
* The {@link NodeMap} will be empty when no child nodes are present.
|
||||||
|
*
|
||||||
|
* @param node the node that shall be represented by this {@link NodeMap}
|
||||||
|
* @throws IllegalArgumentException when argument is null
|
||||||
|
*/
|
||||||
|
public NodeMap(Node node) {
|
||||||
|
if (node == null) {
|
||||||
|
throw new IllegalArgumentException("node cannot be null");
|
||||||
|
}
|
||||||
|
if (node.hasChildNodes()) {
|
||||||
|
mapNodeList(node.getChildNodes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeMap(NodeList nodeList) {
|
||||||
|
if (nodeList == null) {
|
||||||
|
throw new IllegalArgumentException("nodeList cannot be null");
|
||||||
|
}
|
||||||
|
mapNodeList(nodeList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get matching node by {@code LocalName}
|
||||||
|
* In case more than one node matches, it is not guaranteed that the first match is selected
|
||||||
|
*
|
||||||
|
* @param localNames one or more {@code LocalName}s
|
||||||
|
* @return the matching node
|
||||||
|
*/
|
||||||
|
public Optional<Node> getNode(String... localNames) {
|
||||||
|
return getAllNodes(localNames).findAny();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a {@link NodeMap} of the child of a matching node by {@code LocalName}
|
||||||
|
* In case more than one node matches, it is not guaranteed that the first match is selected
|
||||||
|
*
|
||||||
|
* @param localNames one or more {@code LocalName}s
|
||||||
|
* @return the {@link NodeMap} representation of the matching node
|
||||||
|
*/
|
||||||
|
public Optional<NodeMap> getAsNodeMap(String... localNames) {
|
||||||
|
return getNode(localNames).filter(Node::hasChildNodes).map(NodeMap::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the text content of a matching node
|
||||||
|
* In case more than one node matches, it is not guaranteed that the first match is selected
|
||||||
|
*
|
||||||
|
* @param localNames one or more {@code LocalName}s
|
||||||
|
* @return the text content of the matching node
|
||||||
|
*/
|
||||||
|
public Optional<String> getAsString(String... localNames) {
|
||||||
|
return getNode(localNames).map(Node::getTextContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the text content of a matching node
|
||||||
|
* In case more than one node matches, it is not guaranteed that the first match is selected
|
||||||
|
*
|
||||||
|
* @param localNames one or more {@code LocalName}s
|
||||||
|
* @return the text content of the matching node, converted to BigDecimal
|
||||||
|
*/
|
||||||
|
public Optional<BigDecimal> getAsBigDecimal(String... localNames) {
|
||||||
|
return getNode(localNames).map(Node::getTextContent).map(s->new BigDecimal(s.trim()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the text content of a matching node
|
||||||
|
* In case more than one node matches, it is not guaranteed that the first match is selected
|
||||||
|
*
|
||||||
|
* @param localNames one or more {@code LocalName}s
|
||||||
|
* @return the text content of the matching node or {@code null} when no matching node could be found
|
||||||
|
*/
|
||||||
|
public String getAsStringOrNull(String... localNames) {
|
||||||
|
return getAsString(localNames).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all matching nodes
|
||||||
|
*
|
||||||
|
* @param localNames one or more {@code LocalName}s
|
||||||
|
* @return a {@code Stream} that contains all matching nodes (can be empty if nothing matches)
|
||||||
|
*/
|
||||||
|
public Stream<Node> getAllNodes(String... localNames) {
|
||||||
|
List<String> localNamesList = Arrays.asList(localNames);
|
||||||
|
return map.entrySet().stream().filter(e -> localNamesList.contains(e.getKey())).flatMap(e -> e.getValue().stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mapNodeList(NodeList nodeList) {
|
||||||
|
IntStream.range(0, nodeList.getLength()).mapToObj(nodeList::item)
|
||||||
|
.filter(node -> node != null && node.getLocalName() != null)
|
||||||
|
.forEach(node -> map.computeIfAbsent(node.getLocalName(), k -> new ArrayList<>()).add(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return map.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
library/src/main/resources/FreeSans.ttf
Normal file
BIN
library/src/main/resources/FreeSans.ttf
Normal file
Binary file not shown.
@@ -25,7 +25,7 @@
|
|||||||
<renderer mime="application/pdf">
|
<renderer mime="application/pdf">
|
||||||
<fonts><!-- https://xmlgraphics.apache.org/fop/1.1/fonts.html auto-embed -->
|
<fonts><!-- https://xmlgraphics.apache.org/fop/1.1/fonts.html auto-embed -->
|
||||||
<auto-detect/>
|
<auto-detect/>
|
||||||
<font kerning="no" embed-url="FreeSans.ttf" embedding-mode="subset">
|
<font kerning="no" embed-url="classpath:FreeSans.ttf" embedding-mode="subset">
|
||||||
<font-triplet name="SourceSerifPro" style="normal" weight="normal" />
|
<font-triplet name="SourceSerifPro" style="normal" weight="normal" />
|
||||||
<font-triplet name="Times-Bold" style="normal" weight="normal" />
|
<font-triplet name="Times-Bold" style="normal" weight="normal" />
|
||||||
</font>
|
</font>
|
||||||
|
|||||||
2225
library/src/main/resources/stylesheets/cio-xr.xsl
Normal file
2225
library/src/main/resources/stylesheets/cio-xr.xsl
Normal file
File diff suppressed because it is too large
Load Diff
@@ -198,7 +198,7 @@
|
|||||||
<entry key="xr:Third_party_payment_type" id="BT-DEX-001">Art der Fremdforderung</entry>
|
<entry key="xr:Third_party_payment_type" id="BT-DEX-001">Art der Fremdforderung</entry>
|
||||||
<entry key="xr:Third_party_payment_amount" id="BT-DEX-002">Betrag der Fremdforderung</entry>
|
<entry key="xr:Third_party_payment_amount" id="BT-DEX-002">Betrag der Fremdforderung</entry>
|
||||||
<entry key="xr:Third_party_payment_description" id="BT-DEX-003">Beschreibung der Fremdforderung</entry>
|
<entry key="xr:Third_party_payment_description" id="BT-DEX-003">Beschreibung der Fremdforderung</entry>
|
||||||
<entry key="uebersicht">Übersicht</entry>
|
<entry key="uebersicht">Daten der E-Rechnung</entry>
|
||||||
<entry key="uebersichtKaeufer" id="BG-7">Informationen zum Käufer</entry>
|
<entry key="uebersichtKaeufer" id="BG-7">Informationen zum Käufer</entry>
|
||||||
<entry key="uebersichtVerkaeufer" id="BG-4">Informationen zum Verkäufer</entry>
|
<entry key="uebersichtVerkaeufer" id="BG-4">Informationen zum Verkäufer</entry>
|
||||||
<entry key="uebersichtRechnungsInfo" id="invoice-data">Rechnungsdaten</entry>
|
<entry key="uebersichtRechnungsInfo" id="invoice-data">Rechnungsdaten</entry>
|
||||||
@@ -214,7 +214,7 @@
|
|||||||
<entry key="uebersichtZahlungLastschrift" id="BG-19">Lastschrift</entry>
|
<entry key="uebersichtZahlungLastschrift" id="BG-19">Lastschrift</entry>
|
||||||
<entry key="uebersichtZahlungUeberweisung" id="BG-17">Überweisung</entry>
|
<entry key="uebersichtZahlungUeberweisung" id="BG-17">Überweisung</entry>
|
||||||
<entry key="uebersichtBemerkungen" id="BG-1">Bemerkungen zur Rechnung</entry>
|
<entry key="uebersichtBemerkungen" id="BG-1">Bemerkungen zur Rechnung</entry>
|
||||||
<entry key="details">Details</entry>
|
<entry key="details">Rechnungspositionen</entry>
|
||||||
<entry key="detailsPositionAbrechnungszeitraum" id="BG-26">Abrechnungszeitraum</entry>
|
<entry key="detailsPositionAbrechnungszeitraum" id="BG-26">Abrechnungszeitraum</entry>
|
||||||
<entry key="detailsPositionPreiseinzelheiten" id="BG-29">Preiseinzelheiten</entry>
|
<entry key="detailsPositionPreiseinzelheiten" id="BG-29">Preiseinzelheiten</entry>
|
||||||
<entry key="detailsPositionNachlaesse" id="BG-27">Nachlässe auf Ebene der Rechnungsposition</entry>
|
<entry key="detailsPositionNachlaesse" id="BG-27">Nachlässe auf Ebene der Rechnungsposition</entry>
|
||||||
|
|||||||
@@ -807,10 +807,11 @@
|
|||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template name="zusaetzeVertrag">
|
<xsl:template name="zusaetzeVertrag">
|
||||||
<xsl:call-template name="box">
|
<xsl:call-template name="spanned-box">
|
||||||
<xsl:with-param name="identifier" select="'zusaetzeVertrag'"/>
|
<xsl:with-param name="identifier" select="'zusaetzeVertrag'"/>
|
||||||
<xsl:with-param name="content">
|
<xsl:with-param name="content">
|
||||||
<xsl:call-template name="list">
|
<xsl:call-template name="list">
|
||||||
|
<xsl:with-param name="layout" select="'einspaltig'"/>
|
||||||
<xsl:with-param name="content">
|
<xsl:with-param name="content">
|
||||||
<xsl:apply-templates mode="list-entry" select="xr:Tender_or_lot_reference"/>
|
<xsl:apply-templates mode="list-entry" select="xr:Tender_or_lot_reference"/>
|
||||||
<xsl:apply-templates mode="list-entry" select="xr:Receiving_advice_reference"/>
|
<xsl:apply-templates mode="list-entry" select="xr:Receiving_advice_reference"/>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
@@ -65,7 +66,7 @@ public class BackwardCompatibilityTest extends TestCase implements IExportableTr
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ze.export(baos);
|
ze.export(baos);
|
||||||
ze.close();
|
ze.close();
|
||||||
String pdfContent = baos.toString("UTF-8");
|
String pdfContent = baos.toString(StandardCharsets.UTF_8);
|
||||||
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
||||||
// check for pdf-a schema extension
|
// check for pdf-a schema extension
|
||||||
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
||||||
@@ -105,7 +106,7 @@ public class BackwardCompatibilityTest extends TestCase implements IExportableTr
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ze.export(baos);
|
ze.export(baos);
|
||||||
ze.close();
|
ze.close();
|
||||||
String pdfContent = baos.toString("UTF-8");
|
String pdfContent = baos.toString(StandardCharsets.UTF_8);
|
||||||
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
||||||
// check for pdf-a schema extension
|
// check for pdf-a schema extension
|
||||||
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
||||||
@@ -143,7 +144,7 @@ public class BackwardCompatibilityTest extends TestCase implements IExportableTr
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ze.export(baos);
|
ze.export(baos);
|
||||||
ze.close();
|
ze.close();
|
||||||
String pdfContent = baos.toString("UTF-8");
|
String pdfContent = baos.toString(StandardCharsets.UTF_8);
|
||||||
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
||||||
// check for pdf-a schema extension
|
// check for pdf-a schema extension
|
||||||
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
||||||
@@ -316,7 +317,7 @@ public class BackwardCompatibilityTest extends TestCase implements IExportableTr
|
|||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
|
public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
|
||||||
Payment P = new Payment();
|
Payment P = new Payment();
|
||||||
IZUGFeRDTradeSettlementPayment[] allP = new Payment[1];
|
IZUGFeRDTradeSettlementPayment[] allP = new Payment[1];
|
||||||
allP[0] = P;
|
allP[0] = P;
|
||||||
|
|||||||
@@ -22,16 +22,7 @@ import junit.framework.Test;
|
|||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.junit.FixMethodOrder;
|
|
||||||
import org.junit.runners.MethodSorters;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import org.mustangproject.XMLTools;
|
import org.mustangproject.XMLTools;
|
||||||
|
|
||||||
public class BaseTest extends TestCase {
|
public class BaseTest extends TestCase {
|
||||||
@@ -61,6 +52,15 @@ public class BaseTest extends TestCase {
|
|||||||
assertEquals("12.00", XMLTools.nDigitFormat(new BigDecimal("12"),2));
|
assertEquals("12.00", XMLTools.nDigitFormat(new BigDecimal("12"),2));
|
||||||
assertEquals("12", XMLTools.nDigitFormat(new BigDecimal("12"),0));
|
assertEquals("12", XMLTools.nDigitFormat(new BigDecimal("12"),0));
|
||||||
assertEquals("20000123.342", XMLTools.nDigitFormat(new BigDecimal("20000123.3419"),3));
|
assertEquals("20000123.342", XMLTools.nDigitFormat(new BigDecimal("20000123.3419"),3));
|
||||||
|
|
||||||
|
assertEquals("0.00", XMLTools.nDigitFormatDecimalRange(BigDecimal.ZERO,2, 2));
|
||||||
|
assertEquals("-1.10", XMLTools.nDigitFormatDecimalRange(new BigDecimal("-1.100000"), 4,2));
|
||||||
|
assertEquals("-1.101", XMLTools.nDigitFormatDecimalRange(new BigDecimal("-1.101000"),10, 3));
|
||||||
|
assertEquals("-1.10", XMLTools.nDigitFormatDecimalRange(new BigDecimal("-1.103"), 2,2));
|
||||||
|
assertEquals("4", XMLTools.nDigitFormatDecimalRange(new BigDecimal("4"),2, 0));
|
||||||
|
assertEquals("3.14", XMLTools.nDigitFormatDecimalRange(new BigDecimal("3.141526"),2, 0));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mustangproject.util.ByteArraySearcher;
|
||||||
|
|
||||||
|
public class ByteArraySearcherTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testIndexOf () {
|
||||||
|
byte [] haystack = "Hello World".getBytes (StandardCharsets.ISO_8859_1);
|
||||||
|
assertEquals (0, ByteArraySearcher.indexOf (haystack, new byte [] { 'H' }));
|
||||||
|
assertEquals (1, ByteArraySearcher.indexOf (haystack, new byte [] { 'e' }));
|
||||||
|
assertEquals (0, ByteArraySearcher.indexOf (haystack, new byte [] { 'H', 'e' }));
|
||||||
|
assertEquals (0, ByteArraySearcher.indexOf (haystack, new byte [] { 'H', 'e' }));
|
||||||
|
assertEquals (0, ByteArraySearcher.indexOf (haystack, new byte [] { 'H', 'e', 'l', 'l' }));
|
||||||
|
assertEquals (0, ByteArraySearcher.indexOf (haystack, haystack));
|
||||||
|
assertEquals (-1, ByteArraySearcher.indexOf (haystack, new byte [0]));
|
||||||
|
assertEquals (-1, ByteArraySearcher.indexOf (haystack, new byte [] { 'a' }));
|
||||||
|
assertEquals (-1, ByteArraySearcher.indexOf (haystack, new byte [] { 'h' }));
|
||||||
|
assertEquals (-1, ByteArraySearcher.indexOf (haystack, new byte [] { 'r', 'o' }));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartsWith () {
|
||||||
|
byte [] haystack = "Hello World".getBytes (StandardCharsets.ISO_8859_1);
|
||||||
|
assertTrue (ByteArraySearcher.startsWith (haystack, new byte [] { 'H' }));
|
||||||
|
assertFalse (ByteArraySearcher.startsWith (haystack, new byte [] { 'e' }));
|
||||||
|
assertTrue (ByteArraySearcher.startsWith (haystack, new byte [] { 'H', 'e' }));
|
||||||
|
assertTrue (ByteArraySearcher.startsWith (haystack, new byte [] { 'H', 'e' }));
|
||||||
|
assertTrue (ByteArraySearcher.startsWith (haystack, new byte [] { 'H', 'e', 'l', 'l' }));
|
||||||
|
assertTrue (ByteArraySearcher.startsWith (haystack, haystack));
|
||||||
|
assertFalse (ByteArraySearcher.startsWith (haystack, new byte [0]));
|
||||||
|
assertFalse (ByteArraySearcher.startsWith (haystack, new byte [] { 'a' }));
|
||||||
|
assertFalse (ByteArraySearcher.startsWith (haystack, new byte [] { 'h' }));
|
||||||
|
assertFalse (ByteArraySearcher.startsWith (haystack, new byte [] { 'r', 'o' }));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,24 +6,25 @@ import static org.junit.Assert.assertEquals;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mustangproject.*;
|
import org.mustangproject.*;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* tests the linecalculator and transactioncalculator classes
|
* tests the linecalculator and transactioncalculator classes
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class CalculationTest {
|
public class CalculationTest {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(CalculationTest.class);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLineCalculator_simpleAmounts_resultInValidVATAmount() {
|
public void testLineCalculator_simpleAmounts_resultInValidVATAmount() {
|
||||||
final IZUGFeRDExportableProduct product = new IZUGFeRDExportableProductImpl().setVatPercent(valueOf(16));
|
final IZUGFeRDExportableProduct product = new IZUGFeRDExportableProductImpl().setVatPercent(valueOf(16));
|
||||||
final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(100))
|
final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(100))
|
||||||
.setQuantity(TEN)
|
.setQuantity(TEN)
|
||||||
.setProduct(product);
|
.setProduct(product);
|
||||||
|
|
||||||
final LineCalculator calculator = new LineCalculator(currentItem);
|
final LineCalculator calculator = new LineCalculator(currentItem);
|
||||||
|
|
||||||
@@ -40,9 +41,9 @@ public class CalculationTest {
|
|||||||
final IZUGFeRDAllowanceCharge allowance = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(14.8730));
|
final IZUGFeRDAllowanceCharge allowance = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(14.8730));
|
||||||
|
|
||||||
final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(148.73))
|
final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(148.73))
|
||||||
.setQuantity(valueOf(12))
|
.setQuantity(valueOf(12))
|
||||||
.setItemAllowances(new IZUGFeRDAllowanceCharge[]{allowance})
|
.setItemAllowances(new IZUGFeRDAllowanceCharge[]{allowance})
|
||||||
.setProduct(product);
|
.setProduct(product);
|
||||||
|
|
||||||
final LineCalculator calculator = new LineCalculator(currentItem);
|
final LineCalculator calculator = new LineCalculator(currentItem);
|
||||||
|
|
||||||
@@ -59,10 +60,10 @@ public class CalculationTest {
|
|||||||
// 20 % charge
|
// 20 % charge
|
||||||
final IZUGFeRDAllowanceCharge charge = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(29.746));
|
final IZUGFeRDAllowanceCharge charge = new IZUGFeRDAllowanceChargeImpl().setTotalAmount(valueOf(29.746));
|
||||||
final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(148.73))
|
final IZUGFeRDExportableItem currentItem = new IZUGFeRDExportableItemImpl().setPrice(valueOf(148.73))
|
||||||
.setQuantity(valueOf(12))
|
.setQuantity(valueOf(12))
|
||||||
.setItemAllowances(new IZUGFeRDAllowanceCharge[]{allowance})
|
.setItemAllowances(new IZUGFeRDAllowanceCharge[]{allowance})
|
||||||
.setItemCharges(new IZUGFeRDAllowanceCharge[]{charge})
|
.setItemCharges(new IZUGFeRDAllowanceCharge[]{charge})
|
||||||
.setProduct(product);
|
.setProduct(product);
|
||||||
|
|
||||||
final LineCalculator calculator = new LineCalculator(currentItem);
|
final LineCalculator calculator = new LineCalculator(currentItem);
|
||||||
|
|
||||||
@@ -92,111 +93,112 @@ public class CalculationTest {
|
|||||||
invoice.setDeliveryDate(sqlDate.parse("2020-12-31"));
|
invoice.setDeliveryDate(sqlDate.parse("2020-12-31"));
|
||||||
invoice.setDueDate(sqlDate.parse("2021-01-15"));
|
invoice.setDueDate(sqlDate.parse("2021-01-15"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Logger.getLogger(CalculationTest.class.getName()).log(Level.SEVERE, null, e);
|
LOGGER.error("Failed to set dates", e);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* trade party (sender) */
|
/* trade party (sender) */
|
||||||
|
|
||||||
TradeParty sender = new TradeParty("Maier GmbH", "Musterweg 5", "11111", "Testung", "DE");
|
TradeParty sender = new TradeParty("Maier GmbH", "Musterweg 5", "11111", "Testung", "DE");
|
||||||
sender.addVATID("DE2222222222");
|
sender.addVATID("DE2222222222");
|
||||||
invoice.setSender(sender);
|
invoice.setSender(sender);
|
||||||
/* trade party (recipient) */
|
|
||||||
|
|
||||||
|
/* trade party (recipient) */
|
||||||
TradeParty recipient = new TradeParty("Teston GmbH" + " " + "Zentrale" + " " + "", "Testweg 5", "11111", "Testung", "DE");
|
TradeParty recipient = new TradeParty("Teston GmbH" + " " + "Zentrale" + " " + "", "Testweg 5", "11111", "Testung", "DE");
|
||||||
recipient.setID("111111");
|
recipient.setID("111111");
|
||||||
recipient.addVATID("DE111111111");
|
recipient.addVATID("DE111111111");
|
||||||
invoice.setRecipient(recipient);
|
invoice.setRecipient(recipient);
|
||||||
/* item */
|
|
||||||
|
|
||||||
|
/* item */
|
||||||
Product product;
|
Product product;
|
||||||
Item item;
|
Item item;
|
||||||
BigDecimal item_increase = BigDecimal.ZERO;
|
|
||||||
BigDecimal item_discount = BigDecimal.ZERO;
|
|
||||||
|
|
||||||
product = new Product("AAA", "", "H84", sales_tax_percent1).setSellerAssignedID("1AAA");
|
product = new Product("AAA", "", "H84", sales_tax_percent1).setSellerAssignedID("1AAA");
|
||||||
item = new Item(product, new BigDecimal("4.750"), new BigDecimal(5.00));
|
item = new Item(product, new BigDecimal("4.750"), new BigDecimal(5.00));
|
||||||
|
|
||||||
item_discount = new BigDecimal("10.00");
|
// set values for additional charge and discount used for next lines
|
||||||
|
BigDecimal item_increase = BigDecimal.ZERO;
|
||||||
|
BigDecimal item_discount = BigDecimal.valueOf(10.00);
|
||||||
|
|
||||||
|
/* lines */
|
||||||
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
|
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschlag"));
|
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
|
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatt"));
|
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
invoice.addItem(item);
|
invoice.addItem(item);
|
||||||
|
|
||||||
|
// reset values for additional charge and discount used for next lines
|
||||||
|
item_increase = BigDecimal.ZERO;
|
||||||
|
item_discount = BigDecimal.ZERO;
|
||||||
|
|
||||||
product = new Product("BBB", "", "H84", sales_tax_percent1).setSellerAssignedID("2BBB");
|
product = new Product("BBB", "", "H84", sales_tax_percent1).setSellerAssignedID("2BBB");
|
||||||
item = new Item(product, new BigDecimal("5.750"), new BigDecimal(4.00));
|
item = new Item(product, new BigDecimal("5.750"), new BigDecimal(4.00));
|
||||||
item_discount = BigDecimal.ZERO;
|
|
||||||
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
|
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschlag"));
|
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
|
||||||
}
|
}
|
||||||
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
|
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatt"));
|
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
invoice.addItem(item);
|
invoice.addItem(item);
|
||||||
|
|
||||||
product = new Product("CCC", "", "H84", sales_tax_percent1).setSellerAssignedID("3CCC");
|
product = new Product("CCC", "", "H84", sales_tax_percent1).setSellerAssignedID("3CCC");
|
||||||
item = new Item(product, new BigDecimal("6.750"), new BigDecimal(3.00));
|
item = new Item(product, new BigDecimal("6.750"), new BigDecimal(3.00));
|
||||||
item_discount = new BigDecimal("10.00");
|
|
||||||
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
|
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschlag"));
|
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
|
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatt"));
|
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
invoice.addItem(item);
|
invoice.addItem(item);
|
||||||
|
|
||||||
|
|
||||||
product = new Product("DDD", "", "H84", sales_tax_percent1).setSellerAssignedID("4DDD");
|
product = new Product("DDD", "", "H84", sales_tax_percent1).setSellerAssignedID("4DDD");
|
||||||
item = new Item(product, new BigDecimal("7.750"), new BigDecimal(2.00));
|
item = new Item(product, new BigDecimal("7.750"), new BigDecimal(2.00));
|
||||||
|
|
||||||
item_discount = BigDecimal.ZERO;
|
|
||||||
|
|
||||||
|
|
||||||
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
|
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschlag"));
|
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
|
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatt"));
|
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
invoice.addItem(item);
|
invoice.addItem(item);
|
||||||
|
|
||||||
|
|
||||||
product = new Product("EEE", "", "H84", sales_tax_percent1).setSellerAssignedID("5EEE");
|
product = new Product("EEE", "", "H84", sales_tax_percent1).setSellerAssignedID("5EEE");
|
||||||
item = new Item(product, new BigDecimal("8.750"), new BigDecimal(1.00));
|
item = new Item(product, new BigDecimal("8.750"), new BigDecimal(1.00));
|
||||||
|
|
||||||
item_discount = BigDecimal.ZERO;
|
|
||||||
|
|
||||||
|
|
||||||
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
|
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschlag"));
|
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
|
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatt"));
|
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
|
||||||
|
|
||||||
}
|
}
|
||||||
invoice.addItem(item);
|
invoice.addItem(item);
|
||||||
|
|
||||||
if (total_increase_percent.compareTo(BigDecimal.ZERO) > 0) {
|
// reset values for additional charge and discount used on invoice level
|
||||||
invoice.addCharge(new Charge().setPercent(total_increase_percent).setTaxPercent(sales_tax_percent1).setCategoryCode("ZZZ").setReason("Zuschläge"));
|
item_increase = BigDecimal.valueOf(3.50);
|
||||||
}
|
item_discount = BigDecimal.valueOf(10.00);
|
||||||
|
|
||||||
|
if (total_increase_percent.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
invoice.addCharge(new Charge().setPercent(total_increase_percent).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschläge"));
|
||||||
|
}
|
||||||
if (total_discount_percent.compareTo(BigDecimal.ZERO) > 0) {
|
if (total_discount_percent.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
invoice.addAllowance(new Allowance().setPercent(total_discount_percent).setTaxPercent(sales_tax_percent1).setCategoryCode("95").setReason("Rabatte"));
|
invoice.addAllowance(new Allowance().setPercent(total_discount_percent).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatte"));
|
||||||
}
|
}
|
||||||
TransactionCalculator calculator = new TransactionCalculator(invoice);
|
TransactionCalculator calculator = new TransactionCalculator(invoice);
|
||||||
assertEquals(valueOf(99.54).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros());
|
assertEquals(valueOf(101.86).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LineCalculator should not throw an exception when calculating a non-terminating decimal expansion
|
||||||
|
* */
|
||||||
|
@Test
|
||||||
|
public void testNonTerminatingDecimalExpansion() {
|
||||||
|
final Product product = new Product();
|
||||||
|
final IZUGFeRDExportableItem currentItem = new Item().setPrice(valueOf(386.52))
|
||||||
|
.setQuantity(BigDecimal.valueOf(31))
|
||||||
|
.setBasisQuantity(BigDecimal.valueOf(366))
|
||||||
|
.setProduct(product);
|
||||||
|
final LineCalculator calculator = new LineCalculator(currentItem);
|
||||||
|
assertEquals(BigDecimal.valueOf(32.74), calculator.getItemTotalNetAmount());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import java.util.GregorianCalendar;
|
|||||||
import static org.xmlunit.assertj.XmlAssert.assertThat;
|
import static org.xmlunit.assertj.XmlAssert.assertThat;
|
||||||
|
|
||||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
public class DXTest extends MustangReaderTestCase implements IExportableTransaction {
|
public class DXTest extends MustangReaderTestCase {
|
||||||
final String TARGET_PDF = "./target/testout-DX.pdf";
|
final String TARGET_PDF = "./target/testout-DX.pdf";
|
||||||
final String TARGET_XML = "./target/testout-DX.xml";
|
final String TARGET_XML = "./target/testout-DX.xml";
|
||||||
|
|
||||||
|
|||||||
@@ -21,12 +21,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonParseException;
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import org.assertj.core.util.Lists;
|
|
||||||
import org.junit.FixMethodOrder;
|
import org.junit.FixMethodOrder;
|
||||||
import org.junit.runners.MethodSorters;
|
import org.junit.runners.MethodSorters;
|
||||||
import org.mustangproject.*;
|
import org.mustangproject.*;
|
||||||
@@ -39,7 +36,7 @@ public class DeSerializationTest extends TestCase {
|
|||||||
public void testJackson() throws JsonProcessingException {
|
public void testJackson() throws JsonProcessingException {
|
||||||
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty("some org", "teststr", "55232", "teststadt", "DE").addTaxID("taxID")).setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE"))).setNumber("0185").addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal("1"), new BigDecimal(1.0)));
|
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty("some org", "teststr", "55232", "teststadt", "DE").addTaxID("taxID").addBankDetails(new BankDetails("DE3600000123456", "ABCDEFG1001").setAccountName("Donald Duck")).setEmail("info@company.com")).setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE"))).setNumber("0185").addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal("1"), new BigDecimal(1.0)));
|
||||||
String jsonArray = mapper.writeValueAsString(i);
|
String jsonArray = mapper.writeValueAsString(i);
|
||||||
|
|
||||||
// [{"stringValue":"a","intValue":1,"booleanValue":true},
|
// [{"stringValue":"a","intValue":1,"booleanValue":true},
|
||||||
@@ -48,6 +45,90 @@ public class DeSerializationTest extends TestCase {
|
|||||||
Invoice fromJSON = mapper.readValue(jsonArray, Invoice.class);
|
Invoice fromJSON = mapper.readValue(jsonArray, Invoice.class);
|
||||||
assertEquals(fromJSON.getNumber(), i.getNumber());
|
assertEquals(fromJSON.getNumber(), i.getNumber());
|
||||||
assertEquals(fromJSON.getZFItems().length, i.getZFItems().length);
|
assertEquals(fromJSON.getZFItems().length, i.getZFItems().length);
|
||||||
|
assertEquals("info@company.com", fromJSON.getSender().getEmail());
|
||||||
|
assertEquals("info@company.com", fromJSON.getSender().getUriUniversalCommunicationID());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testAllowanceRead() throws JsonProcessingException {
|
||||||
|
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
// [{"stringValue":"a","intValue":1,"booleanValue":true},
|
||||||
|
// {"stringValue":"bc","intValue":3,"booleanValue":false}]
|
||||||
|
|
||||||
|
Invoice fromJSON = mapper.readValue("{\n" +
|
||||||
|
" \"documentCode\": \"380\",\n" +
|
||||||
|
" \"number\": \"471102\",\n" +
|
||||||
|
" \"ownOrganisationName\": \"Lieferant GmbH\",\n" +
|
||||||
|
" \"currency\": \"EUR\",\n" +
|
||||||
|
" \"issueDate\": \"2018-03-03T23:00:00.000+00:00\",\n" +
|
||||||
|
" \"deliveryDate\": \"2018-03-03T23:00:00.000+00:00\",\n" +
|
||||||
|
" \"sender\": {\n" +
|
||||||
|
" \"name\": \"Lieferant GmbH\",\n" +
|
||||||
|
" \"zip\": \"80333\",\n" +
|
||||||
|
" \"street\": \"Lieferantenstraße 20\",\n" +
|
||||||
|
" \"location\": \"München\",\n" +
|
||||||
|
" \"country\": \"DE\",\n" +
|
||||||
|
" \"taxID\": \"201/113/40209\",\n" +
|
||||||
|
" \"vatID\": \"DE123456789\",\n" +
|
||||||
|
" \"vatid\": \"DE123456789\"\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"recipient\": {\n" +
|
||||||
|
" \"name\": \"Kunden AG Mitte\",\n" +
|
||||||
|
" \"zip\": \"69876\",\n" +
|
||||||
|
" \"street\": \"Kundenstraße 15\",\n" +
|
||||||
|
" \"location\": \"Frankfurt\",\n" +
|
||||||
|
" \"country\": \"DE\"\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"grandTotal\": 234.43,\n" +
|
||||||
|
" \"zfitems\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"price\": 9.9,\n" +
|
||||||
|
" \"quantity\": 20,\n" +
|
||||||
|
" \"tax\": null,\n" +
|
||||||
|
" \"grossPrice\": null,\n" +
|
||||||
|
" \"lineTotalAmount\": null,\n" +
|
||||||
|
" \"basisQuantity\": 1,\n" +
|
||||||
|
" \"detailedDeliveryPeriodFrom\": null,\n" +
|
||||||
|
" \"detailedDeliveryPeriodTo\": null,\n" +
|
||||||
|
" \"id\": null,\n" +
|
||||||
|
" \"product\": {\n" +
|
||||||
|
" \"unit\": \"H87\",\n" +
|
||||||
|
" \"name\": \"Trennblätter A4\",\n" +
|
||||||
|
" \"taxCategoryCode\": \"S\",\n" +
|
||||||
|
" \"attributes\": null,\n" +
|
||||||
|
" \"vatpercent\": 19\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"value\": 9.9\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ],\n" +
|
||||||
|
" \"tradeSettlement\": null,\n" +
|
||||||
|
" \"ownTaxID\": \"201/113/40209\",\n" +
|
||||||
|
" \"ownVATID\": \"DE123456789\",\n" +
|
||||||
|
" \"ownStreet\": \"Lieferantenstraße 20\",\n" +
|
||||||
|
" \"ownZIP\": \"80333\",\n" +
|
||||||
|
" \"ownLocation\": \"München\",\n" +
|
||||||
|
" \"ownCountry\": \"DE\",\n" +
|
||||||
|
" \"zfallowances\": [\n" +
|
||||||
|
" {\n" +
|
||||||
|
" \"totalAmount\": 1,\n" +
|
||||||
|
" \"taxPercent\": 19,\n" +
|
||||||
|
" \"reason\": \"Sondernachlass\",\n" +
|
||||||
|
" \"reasonCode\": null,\n" +
|
||||||
|
" \"categoryCode\": \"S\",\n" +
|
||||||
|
" \"charge\": false\n" +
|
||||||
|
" }\n" +
|
||||||
|
" ]\n" +
|
||||||
|
"}", Invoice.class);
|
||||||
|
TransactionCalculator tc=new TransactionCalculator(fromJSON);
|
||||||
|
assertEquals(tc.getGrandTotal(),new BigDecimal("234.43"));
|
||||||
|
assertEquals(fromJSON.getNumber(), fromJSON.getNumber());
|
||||||
|
assertEquals(fromJSON.getZFItems().length, fromJSON.getZFItems().length);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import java.math.BigDecimal;
|
|||||||
public class IZUGFeRDAllowanceChargeImpl implements IZUGFeRDAllowanceCharge {
|
public class IZUGFeRDAllowanceChargeImpl implements IZUGFeRDAllowanceCharge {
|
||||||
private BigDecimal totalAmount;
|
private BigDecimal totalAmount;
|
||||||
private String reason;
|
private String reason;
|
||||||
|
private String reasonCode;
|
||||||
private BigDecimal taxPercent;
|
private BigDecimal taxPercent;
|
||||||
boolean isCharge=true;
|
boolean isCharge=true;
|
||||||
|
|
||||||
@@ -36,6 +37,11 @@ public class IZUGFeRDAllowanceChargeImpl implements IZUGFeRDAllowanceCharge {
|
|||||||
return reason;
|
return reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getReasonCode() {
|
||||||
|
return reasonCode;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BigDecimal getTaxPercent() {
|
public BigDecimal getTaxPercent() {
|
||||||
return taxPercent;
|
return taxPercent;
|
||||||
@@ -61,6 +67,11 @@ public class IZUGFeRDAllowanceChargeImpl implements IZUGFeRDAllowanceCharge {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IZUGFeRDAllowanceChargeImpl setReasonCode(String reasonCode) {
|
||||||
|
this.reasonCode = reasonCode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public IZUGFeRDAllowanceChargeImpl setTaxPercent(BigDecimal taxPercent) {
|
public IZUGFeRDAllowanceChargeImpl setTaxPercent(BigDecimal taxPercent) {
|
||||||
this.taxPercent = taxPercent;
|
this.taxPercent = taxPercent;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -256,13 +256,13 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
|
|||||||
"</ram:ApplicableHeaderTradeSettlement>\n" +
|
"</ram:ApplicableHeaderTradeSettlement>\n" +
|
||||||
"</rsm:SupplyChainTradeTransaction>\n" +
|
"</rsm:SupplyChainTradeTransaction>\n" +
|
||||||
"</rsm:CrossIndustryInvoice>";
|
"</rsm:CrossIndustryInvoice>";
|
||||||
zea1.setXML(ownZUGFeRDXML.getBytes("UTF-8"));
|
zea1.setXML(ownZUGFeRDXML.getBytes(StandardCharsets.UTF_8));
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
zea1.disableAutoClose(true);
|
zea1.disableAutoClose(true);
|
||||||
zea1.export(TARGET_PDF);
|
zea1.export(TARGET_PDF);
|
||||||
zea1.export(baos);
|
zea1.export(baos);
|
||||||
zea1.close();
|
zea1.close();
|
||||||
String pdfContent = baos.toString("UTF-8");
|
String pdfContent = baos.toString(StandardCharsets.UTF_8);
|
||||||
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
||||||
assertFalse(pdfContent.indexOf("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>") == -1);
|
assertFalse(pdfContent.indexOf("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>") == -1);
|
||||||
|
|
||||||
@@ -437,14 +437,14 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
|
|||||||
+ "<ram:Name>Heiße Luft pro Liter</ram:Name>\n" + "<ram:Description/>\n"
|
+ "<ram:Name>Heiße Luft pro Liter</ram:Name>\n" + "<ram:Description/>\n"
|
||||||
+ "</ram:SpecifiedTradeProduct>\n" + "</ram:IncludedSupplyChainTradeLineItem>\n"
|
+ "</ram:SpecifiedTradeProduct>\n" + "</ram:IncludedSupplyChainTradeLineItem>\n"
|
||||||
+ "</rsm:SpecifiedSupplyChainTradeTransaction>\n" + "</rsm:CrossIndustryDocument>";
|
+ "</rsm:SpecifiedSupplyChainTradeTransaction>\n" + "</rsm:CrossIndustryDocument>";
|
||||||
zea1.setXML(ownZUGFeRDXML.getBytes("UTF-8"));
|
zea1.setXML(ownZUGFeRDXML.getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
zea1.disableAutoClose(true);
|
zea1.disableAutoClose(true);
|
||||||
zea1.export(TARGET_PDF);
|
zea1.export(TARGET_PDF);
|
||||||
zea1.export(baos);
|
zea1.export(baos);
|
||||||
zea1.close();
|
zea1.close();
|
||||||
String pdfContent = baos.toString("UTF-8");
|
String pdfContent = baos.toString(StandardCharsets.UTF_8);
|
||||||
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
||||||
assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>BASIC</zf:ConformanceLevel>") == -1);
|
assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>BASIC</zf:ConformanceLevel>") == -1);
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package org.mustangproject.ZUGFeRD;
|
|||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
||||||
import org.apache.xmpbox.XMPMetadata;
|
import org.apache.xmpbox.XMPMetadata;
|
||||||
@@ -42,7 +43,7 @@ import java.util.GregorianCalendar;
|
|||||||
|
|
||||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
|
public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
|
||||||
protected class EasyRecipientTradeParty extends RecipientTradeParty implements IZUGFeRDExportableTradeParty {
|
protected class EasyRecipientTradeParty extends RecipientTradeParty {
|
||||||
// Not testing extended profile here, lineThree not possible
|
// Not testing extended profile here, lineThree not possible
|
||||||
@Override
|
@Override
|
||||||
public String getAdditionalAddressExtension() {
|
public String getAdditionalAddressExtension() {
|
||||||
@@ -252,7 +253,7 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
|
|||||||
setupPdfUnderTest(SOURCE_PDF, TARGET_PDF);
|
setupPdfUnderTest(SOURCE_PDF, TARGET_PDF);
|
||||||
|
|
||||||
// now check the contents
|
// now check the contents
|
||||||
PDDocument doc = PDDocument.load(new File(TARGET_PDF));
|
PDDocument doc = Loader.loadPDF(new File(TARGET_PDF));
|
||||||
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
|
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
|
||||||
assertNotNull("The pdf must contain XMPMetadata", meta);
|
assertNotNull("The pdf must contain XMPMetadata", meta);
|
||||||
|
|
||||||
@@ -262,7 +263,7 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase {
|
|||||||
DomXmpParser xmpParser = new DomXmpParser();
|
DomXmpParser xmpParser = new DomXmpParser();
|
||||||
XMPMetadata xmp = xmpParser.parse(xmpBytes);
|
XMPMetadata xmp = xmpParser.parse(xmpBytes);
|
||||||
|
|
||||||
PDFAIdentificationSchema pdfai = xmp.getPDFIdentificationSchema();
|
PDFAIdentificationSchema pdfai = xmp.getPDFAIdentificationSchema();
|
||||||
assertNotNull("The pdf must contain a PDFIdentificationSchema", pdfai);
|
assertNotNull("The pdf must contain a PDFIdentificationSchema", pdfai);
|
||||||
|
|
||||||
assertTrue("The PDF/A conformance must be A, B or U",
|
assertTrue("The PDF/A conformance must be A, B or U",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package org.mustangproject.ZUGFeRD;
|
|||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
||||||
import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
|
import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
|
||||||
@@ -38,6 +39,7 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -212,8 +214,10 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
|||||||
|
|
||||||
public void testForeignImport() {
|
public void testForeignImport() {
|
||||||
InputStream inputStream = this.getClass().getResourceAsStream("/zugferd_invoice.pdf");
|
InputStream inputStream = this.getClass().getResourceAsStream("/zugferd_invoice.pdf");
|
||||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream);
|
ZUGFeRDImporter zi = new ZUGFeRDImporter();
|
||||||
|
zi.doRecalculateItemPricesFromLineTotals();
|
||||||
|
zi.doIgnoreCalculationErrors();
|
||||||
|
zi.setInputStream(inputStream);
|
||||||
// Reading ZUGFeRD
|
// Reading ZUGFeRD
|
||||||
String amount = zi.getAmount();
|
String amount = zi.getAmount();
|
||||||
|
|
||||||
@@ -328,13 +332,13 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkPdfA3B(File tempFile) throws IOException, InvalidPasswordException {
|
private void checkPdfA3B(File tempFile) throws IOException, InvalidPasswordException {
|
||||||
try (PDDocument doc = PDDocument.load(tempFile)) {
|
try (PDDocument doc = Loader.loadPDF(tempFile)) {
|
||||||
PDMetadata metadata = doc.getDocumentCatalog().getMetadata();
|
PDMetadata metadata = doc.getDocumentCatalog().getMetadata();
|
||||||
InputStream exportXMPMetadata = metadata.exportXMPMetadata();
|
InputStream exportXMPMetadata = metadata.exportXMPMetadata();
|
||||||
byte[] xmpBytes = new byte[exportXMPMetadata.available()];
|
byte[] xmpBytes = new byte[exportXMPMetadata.available()];
|
||||||
exportXMPMetadata.read(xmpBytes);
|
exportXMPMetadata.read(xmpBytes);
|
||||||
final XMPMetadata xmp = new DomXmpParser().parse(xmpBytes);
|
final XMPMetadata xmp = new DomXmpParser().parse(xmpBytes);
|
||||||
PDFAIdentificationSchema pdfaid = xmp.getPDFIdentificationSchema();
|
PDFAIdentificationSchema pdfaid = xmp.getPDFAIdentificationSchema();
|
||||||
assertEquals(pdfaid.getPart().intValue(), 3);
|
assertEquals(pdfaid.getPart().intValue(), 3);
|
||||||
assertEquals(pdfaid.getConformance(), "U");
|
assertEquals(pdfaid.getConformance(), "U");
|
||||||
} catch (XmpParsingException e) {
|
} catch (XmpParsingException e) {
|
||||||
@@ -367,7 +371,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ze.export(baos);
|
ze.export(baos);
|
||||||
ze.close();
|
ze.close();
|
||||||
String pdfContent = baos.toString("UTF-8");
|
String pdfContent = baos.toString(StandardCharsets.UTF_8);
|
||||||
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
||||||
// check for pdf-a schema extension
|
// check for pdf-a schema extension
|
||||||
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
||||||
@@ -411,7 +415,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ze.export(baos);
|
ze.export(baos);
|
||||||
ze.close();
|
ze.close();
|
||||||
String pdfContent = baos.toString("UTF-8");
|
String pdfContent = baos.toString(StandardCharsets.UTF_8);
|
||||||
assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.BASIC) >= 0);
|
assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.BASIC) >= 0);
|
||||||
assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.EXTENDED) >= 0);
|
assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.EXTENDED) >= 0);
|
||||||
assertTrue(pdfContent.indexOf(DocumentContextParameterTypeConstants.COMFORT) >= 0);
|
assertTrue(pdfContent.indexOf(DocumentContextParameterTypeConstants.COMFORT) >= 0);
|
||||||
@@ -447,7 +451,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ze.export(baos);
|
ze.export(baos);
|
||||||
ze.close();
|
ze.close();
|
||||||
String pdfContent = baos.toString("UTF-8");
|
String pdfContent = baos.toString(StandardCharsets.UTF_8);
|
||||||
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
||||||
// check for pdf-a schema extension
|
// check for pdf-a schema extension
|
||||||
assertFalse(pdfContent.indexOf("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>") == -1);
|
assertFalse(pdfContent.indexOf("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>") == -1);
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import org.junit.runners.MethodSorters;
|
|||||||
import org.mustangproject.*;
|
import org.mustangproject.*;
|
||||||
|
|
||||||
import javax.xml.xpath.XPathExpressionException;
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -42,7 +41,7 @@ import java.util.Date;
|
|||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
public class OXTest extends MustangReaderTestCase implements IExportableTransaction {
|
public class OXTest extends MustangReaderTestCase {
|
||||||
final String TARGET_PDF = "./target/testout-OX.pdf";
|
final String TARGET_PDF = "./target/testout-OX.pdf";
|
||||||
final String TARGET_PDF_EDGE = "./target/testout-OX-edge.pdf";
|
final String TARGET_PDF_EDGE = "./target/testout-OX-edge.pdf";
|
||||||
final String TARGET_XML = "./target/testout-OX.xml";
|
final String TARGET_XML = "./target/testout-OX.xml";
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* *********************************************************************
|
||||||
|
* <p>
|
||||||
|
* Copyright 2019 Jochen Staerk
|
||||||
|
* <p>
|
||||||
|
* Use is subject to license terms.
|
||||||
|
* <p>
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy
|
||||||
|
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
* <p>
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* <p>
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* <p>
|
||||||
|
* **********************************************************************
|
||||||
|
*/
|
||||||
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.junit.FixMethodOrder;
|
||||||
|
import org.junit.runners.MethodSorters;
|
||||||
|
import org.mustangproject.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
|
public class PreValidationTest extends TestCase {
|
||||||
|
final String TARGET_PDF = "./target/testout-Preval.pdf";
|
||||||
|
final String SOURCE_PDF = "/veraPDFtestsuite6-7-11-t01-fail-a.pdf";
|
||||||
|
|
||||||
|
public void testFailIgnore() {
|
||||||
|
|
||||||
|
// the writing part
|
||||||
|
|
||||||
|
|
||||||
|
boolean hasEx = false;
|
||||||
|
try (InputStream source = this.getClass()
|
||||||
|
.getResourceAsStream(SOURCE_PDF)) {
|
||||||
|
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
|
||||||
|
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2)
|
||||||
|
.load(source);
|
||||||
|
ze.setTransaction(createInvoice());
|
||||||
|
|
||||||
|
ze.export(TARGET_PDF);
|
||||||
|
} catch (IOException e) {
|
||||||
|
hasEx = true;
|
||||||
|
}
|
||||||
|
assertTrue(hasEx);
|
||||||
|
hasEx = false;
|
||||||
|
try (InputStream source = this.getClass()
|
||||||
|
.getResourceAsStream(SOURCE_PDF)) {
|
||||||
|
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
|
||||||
|
ze.ignorePDFAErrors().load(source);
|
||||||
|
|
||||||
|
ze.setProducer("My Application").setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).
|
||||||
|
setTransaction(createInvoice());
|
||||||
|
ze.export(TARGET_PDF);
|
||||||
|
} catch (IOException e) {
|
||||||
|
hasEx = true;
|
||||||
|
}
|
||||||
|
assertFalse(hasEx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Invoice createInvoice() {
|
||||||
|
String orgname = "Test company";
|
||||||
|
String number = "123";
|
||||||
|
String amountStr = "1.00";
|
||||||
|
BigDecimal amount = new BigDecimal(amountStr);
|
||||||
|
return new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
|
||||||
|
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("DE4711").addVATID("DE0815").setEmail("info@example.org").setContact(new Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new BankDetails("DE12500105170648489890", "COBADEFXXX")))
|
||||||
|
.setRecipient(new TradeParty("Theodor Est", "Bahnstr. 42", "88802", "Spielkreis", "DE"))
|
||||||
|
.setReferenceNumber("991-01484-64")//leitweg-id
|
||||||
|
// not using any VAT, this is also a test of zero-rated goods:
|
||||||
|
.setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO), amount, new BigDecimal(1.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -23,13 +23,10 @@ package org.mustangproject.ZUGFeRD;
|
|||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import org.mustangproject.*;
|
import org.mustangproject.*;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* This is a test to confirm the minimum steps to implement a interface are still sufficient
|
* This is a test to confirm the minimum steps to implement a interface are still sufficient
|
||||||
@@ -39,7 +36,8 @@ import java.util.GregorianCalendar;
|
|||||||
*/
|
*/
|
||||||
public class ProfilesMinimumBasicWLTest extends TestCase {
|
public class ProfilesMinimumBasicWLTest extends TestCase {
|
||||||
|
|
||||||
final String TARGET_PDF_FX_MINIMUM = "./target/testout-Minimum.pdf";
|
final String TARGET_PDF_FX_MINIMUM_INV = "./target/testout-Minimum-INV.pdf";
|
||||||
|
final String TARGET_PDF_FX_MINIMUM_CN = "./target/testout-Minimum-CN.pdf";
|
||||||
|
|
||||||
public void testMinimumCreditNote() {
|
public void testMinimumCreditNote() {
|
||||||
String ownNumber = "NUMFACTURE";
|
String ownNumber = "NUMFACTURE";
|
||||||
@@ -63,14 +61,14 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
|
|||||||
Invoice i = new Invoice()
|
Invoice i = new Invoice()
|
||||||
.setIssueDate(new Date())
|
.setIssueDate(new Date())
|
||||||
.setSender(
|
.setSender(
|
||||||
new TradeParty().setName(ownOrgName).setCountry("FR")
|
new TradeParty().setName(ownOrgName).setCountry("FR").setVATID("FR555444333222111")
|
||||||
.addBankDetails(new BankDetails(ownIBAN, ownBIC)))
|
.addBankDetails(new BankDetails(ownIBAN, ownBIC)))
|
||||||
.setRecipient(recipient)
|
.setRecipient(recipient)
|
||||||
.setNumber(ownNumber)
|
.setNumber(ownNumber)
|
||||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(123), new BigDecimal(1)))
|
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(123), new BigDecimal(1)))
|
||||||
.setCreditNote();
|
.setCreditNote();
|
||||||
ze.setTransaction(i);
|
ze.setTransaction(i);
|
||||||
ze.export(TARGET_PDF_FX_MINIMUM);
|
ze.export(TARGET_PDF_FX_MINIMUM_CN);
|
||||||
|
|
||||||
// check for pdf-a schema extension
|
// check for pdf-a schema extension
|
||||||
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
||||||
@@ -82,7 +80,7 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// now check the contents (like MustangReaderTest)
|
// now check the contents (like MustangReaderTest)
|
||||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX_MINIMUM);
|
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX_MINIMUM_CN);
|
||||||
|
|
||||||
// Reading ZUGFeRD
|
// Reading ZUGFeRD
|
||||||
assertEquals("146.37",zi.getAmount());
|
assertEquals("146.37",zi.getAmount());
|
||||||
@@ -118,13 +116,13 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
|
|||||||
.setIssueDate(new Date())
|
.setIssueDate(new Date())
|
||||||
.setDueDate(new Date())
|
.setDueDate(new Date())
|
||||||
.setSender(
|
.setSender(
|
||||||
new TradeParty().setName(ownOrgName).setCountry("FR")
|
new TradeParty().setName(ownOrgName).setCountry("FR").setVATID("FR555444333222111")
|
||||||
.addBankDetails(new BankDetails(ownIBAN)))
|
.addBankDetails(new BankDetails(ownIBAN)))
|
||||||
.setRecipient(recipient)
|
.setRecipient(recipient)
|
||||||
.setNumber(ownNumber).setTotalPrepaidAmount(new BigDecimal("1"))
|
.setNumber(ownNumber).setTotalPrepaidAmount(new BigDecimal("1"))
|
||||||
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(123), new BigDecimal(1)));
|
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(123), new BigDecimal(1)));
|
||||||
ze.setTransaction(i);
|
ze.setTransaction(i);
|
||||||
ze.export(TARGET_PDF_FX_MINIMUM);
|
ze.export(TARGET_PDF_FX_MINIMUM_INV);
|
||||||
|
|
||||||
// check for pdf-a schema extension
|
// check for pdf-a schema extension
|
||||||
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
|
||||||
@@ -136,10 +134,10 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// now check the contents (like MustangReaderTest)
|
// now check the contents (like MustangReaderTest)
|
||||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX_MINIMUM);
|
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX_MINIMUM_INV);
|
||||||
|
|
||||||
// Reading ZUGFeRD
|
// Reading ZUGFeRD
|
||||||
assertEquals("145.37",zi.getAmount());
|
assertEquals("146.37",zi.getAmount());
|
||||||
// assertEquals(zi.getBIC(), ownBIC);
|
// assertEquals(zi.getBIC(), ownBIC);
|
||||||
// assertEquals(zi.getIBAN(), ownIBAN);
|
// assertEquals(zi.getIBAN(), ownIBAN);
|
||||||
assertEquals(ownOrgName, zi.getHolder());
|
assertEquals(ownOrgName, zi.getHolder());
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -9,6 +11,7 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
@Ignore
|
||||||
public class ResourceCase extends TestCase {
|
public class ResourceCase extends TestCase {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceCase.class.getCanonicalName()); // log output is
|
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceCase.class.getCanonicalName()); // log output is
|
||||||
|
|
||||||
|
|||||||
@@ -22,15 +22,16 @@ import java.net.URISyntaxException;
|
|||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test utility class is providing usability functions to test file resources
|
* This test utility class is providing usability functions to test file resources
|
||||||
*/
|
*/
|
||||||
public class ResourceUtilities {
|
public class ResourceUtilities {
|
||||||
private static final Logger LOG = Logger.getLogger(ResourceUtilities.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger (ResourceUtilities.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loading a File into a String using a certain encoding and file path
|
* Loading a File into a String using a certain encoding and file path
|
||||||
@@ -73,7 +74,7 @@ public class ResourceUtilities {
|
|||||||
uri = ResourceUtilities.class.getClassLoader().getResource(relativeFilePath).toURI();
|
uri = ResourceUtilities.class.getClassLoader().getResource(relativeFilePath).toURI();
|
||||||
uri = new URI(toExternalForm(uri));
|
uri = new URI(toExternalForm(uri));
|
||||||
} catch (URISyntaxException ex) {
|
} catch (URISyntaxException ex) {
|
||||||
LOG.log(Level.SEVERE, null, ex);
|
LOGGER.error("Failed to parse URI", ex);
|
||||||
}
|
}
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
throw new FileNotFoundException("Could not find the file '" + relativeFilePath + "'!");
|
throw new FileNotFoundException("Could not find the file '" + relativeFilePath + "'!");
|
||||||
@@ -129,7 +130,7 @@ public class ResourceUtilities {
|
|||||||
try {
|
try {
|
||||||
filepath = ResourceUtilities.class.getClassLoader().getResource("").toURI().getPath() + relativeFilePath;
|
filepath = ResourceUtilities.class.getClassLoader().getResource("").toURI().getPath() + relativeFilePath;
|
||||||
} catch (URISyntaxException ex) {
|
} catch (URISyntaxException ex) {
|
||||||
LOG.log(Level.SEVERE, null, ex);
|
LOGGER.error("Failed to parse URI", ex);
|
||||||
}
|
}
|
||||||
return new File(filepath);
|
return new File(filepath);
|
||||||
}
|
}
|
||||||
@@ -142,7 +143,7 @@ public class ResourceUtilities {
|
|||||||
try {
|
try {
|
||||||
testFolder = ResourceUtilities.class.getClassLoader().getResource("").toURI().getPath();
|
testFolder = ResourceUtilities.class.getClassLoader().getResource("").toURI().getPath();
|
||||||
} catch (URISyntaxException ex) {
|
} catch (URISyntaxException ex) {
|
||||||
LOG.log(Level.SEVERE, null, ex);
|
LOGGER.error("Failed to parse URI", ex);
|
||||||
}
|
}
|
||||||
return testFolder;
|
return testFolder;
|
||||||
}
|
}
|
||||||
@@ -206,7 +207,7 @@ public class ResourceUtilities {
|
|||||||
try {
|
try {
|
||||||
ret = new URI(sb.toString()).toASCIIString();
|
ret = new URI(sb.toString()).toASCIIString();
|
||||||
} catch (URISyntaxException ex) {
|
} catch (URISyntaxException ex) {
|
||||||
LOG.log(Level.SEVERE, null, ex);
|
LOGGER.error("Failed to parse URI", ex);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ public class UBLTest extends ResourceCase {
|
|||||||
final ByteArrayOutputStream baos=new ByteArrayOutputStream();
|
final ByteArrayOutputStream baos=new ByteArrayOutputStream();
|
||||||
oe.export(baos);
|
oe.export(baos);
|
||||||
|
|
||||||
final String theXML = baos.toString("UTF-8");
|
final String theXML = baos.toString(StandardCharsets.UTF_8);
|
||||||
assertTrue(theXML.contains("<DespatchAdvice"));
|
assertTrue(theXML.contains("<DespatchAdvice"));
|
||||||
Files.write(Paths.get(TARGET_XML), theXML.getBytes(StandardCharsets.UTF_8));
|
Files.write(Paths.get(TARGET_XML), theXML.getBytes(StandardCharsets.UTF_8));
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
@@ -123,33 +123,8 @@ public class UBLTest extends ResourceCase {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testEdgeInvoiceImportUBL2() {
|
||||||
public void testInvoiceImportOtherUBL() {
|
File UBLinputFile = getResourceAsFile("ubl/04.01a-INVOICE_ubl.xml");
|
||||||
|
|
||||||
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_2_Teilrechnung.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_AbweichenderZahlungsempf.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Betriebskostenabrechnung.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Einfach.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Einfach_DueDate.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Einfach_negativePaymentDue.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Elektron.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_ElektronischeAdresse.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Gutschrift.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Haftpflichtversicherung_Versicherungssteuer.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Innergemeinschaftliche_Lieferungen.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Kraftfahrversicherung_Bruttopreise.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Miete.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_OEPNV.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Physiotherapeut.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Rabatte.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Rechnungskorrektur.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_RechnungsUebertragung.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Reisekostenabrechnung.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_Sachversicherung_berechneter_Steuersatz.ubl.xml");
|
|
||||||
File UBLinputFile = getResourceAsFile("EN16931_SEPA_Prenotification.ubl.xml");
|
|
||||||
|
|
||||||
File UBLinputFile = getResourceAsFile("ubl/EN16931_1_Teilrechnung.ubl.xml");
|
|
||||||
boolean hasExceptions = false;
|
boolean hasExceptions = false;
|
||||||
|
|
||||||
ZUGFeRDInvoiceImporter zii = null;
|
ZUGFeRDInvoiceImporter zii = null;
|
||||||
@@ -158,15 +133,12 @@ public class UBLTest extends ResourceCase {
|
|||||||
zii = new ZUGFeRDInvoiceImporter(new FileInputStream(UBLinputFile));
|
zii = new ZUGFeRDInvoiceImporter(new FileInputStream(UBLinputFile));
|
||||||
invoice = zii.extractInvoice();
|
invoice = zii.extractInvoice();
|
||||||
} catch (XPathExpressionException | ParseException | FileNotFoundException e) {
|
} catch (XPathExpressionException | ParseException | FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
hasExceptions = true;
|
hasExceptions = true;
|
||||||
}
|
}
|
||||||
assertFalse(hasExceptions);
|
assertFalse(hasExceptions);
|
||||||
// Reading ZUGFeRD
|
|
||||||
assertEquals(new BigDecimal("288.79"), invoice.getZFItems()[0].getPrice());
|
|
||||||
assertEquals("04011000-12345-03", invoice.getReferenceNumber());
|
|
||||||
assertEquals("seller@email.de", invoice.getSender().getContact().getEMail());
|
|
||||||
assertEquals("12345", invoice.getRecipient().getZIP());
|
|
||||||
assertEquals("DE75512108001245126199", invoice.getSender().getBankDetails().get(0).getIBAN());
|
|
||||||
|
|
||||||
|
assertEquals(new BigDecimal("10000.0"), invoice.getTotalPrepaidAmount());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user