diff --git a/History.md b/History.md index 42272163..81ce7e8c 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,52 @@ +1.7.4 +===== + +- #102 XML entities for ZF2 export + + +1.7.3 +===== +2019-08-01 + +- #105 does not build in windows +- #99 BOMs confuse parser +- updated javadoc +- fixed #104 nullpointerex when specifying no parameter +- PR #112 complete profile options for v1 +- access to TotalPrepaidAmount in ZF v1 #118 +- have unit tests for nDigitFormat #23 + + +1.7.2 +===== +2019-07-08 + +Support BuyerReference (r+w), as well as SpecifiedLegalOrganization (w) and DefinedTradeContact (w) +use dom4j to format output xml document +corrected some exception logging glitches +upgrade PDFBox to 2.0.15+ +extraction to use proper filename instead of alias #98 +NullPointerException in ZUGFeRDImporter.extractLowLevel #96 +Removed Bankleitzahl from ZF2 + + +1.7.1 +===== +2019-05-26 + +Corrected EN16931 ZF2 profile name + +1.7.0 +===== +2019-05-05 + +Export ZF2 final now seems halfway valid (new filename, new namespace prefixa) +Migrates profile names in ZF1 to ZF2 migration +Nullpointerex solved with certain invalid profiles +Be able to access additional files ("additional data") +Known bugs: src/test/resources/migration/reference/ZUGFeRD2_EXTENDED_Warenrechnung.xml is invalid + + 1.6.0 ===== 2019-02-03 diff --git a/README.md b/README.md index d38d0088..bc41c36f 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ As dependency use this org.mustangproject.ZUGFeRD mustang - 1.5.4 + 1.7.1 diff --git a/ZUGFeRD-invoice.xml b/ZUGFeRD-invoice.xml deleted file mode 100644 index e69de29b..00000000 diff --git a/doc/MustangWriter.java b/doc/MustangWriter.java index 91c2cfe1..500923dc 100644 --- a/doc/MustangWriter.java +++ b/doc/MustangWriter.java @@ -5,12 +5,15 @@ import java.math.BigDecimal; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import java.util.logging.Level; +import java.util.logging.Logger; import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTransaction; +import org.mustangproject.ZUGFeRD.ZUGFeRD2PullProvider; import org.mustangproject.ZUGFeRD.ZUGFeRDExporter; import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1Factory; @@ -32,8 +35,7 @@ public class MustangWriter implements IZUGFeRDExportableTransaction { ze.export("./MustangGnuaccountingBeispielRE-20171118_506new.pdf"); System.out.println("Done."); } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Logger.getLogger(MustangWriter.class.getName()).log(Level.SEVERE, null, e1); } } diff --git a/doc/development_documentation.md b/doc/development_documentation.md new file mode 100644 index 00000000..f9439a5e --- /dev/null +++ b/doc/development_documentation.md @@ -0,0 +1,97 @@ +## New build + +Target platform is java 1.7 + +## Build + +Toecount is now part of the package which can be build with +``` +mvn clean package +``` + +## Test + +`package -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8001 -Xnoagent -Djava.compiler=NONE"` +can be used as debug configuration goal in Eclipse. In that case you can set breakpoints in tests. + +## Validate + +[ZUV](https://github.com/ZUGFeRD/ZUV/) can be used to validate generated files. + +## Deployment + +A section in Maven's settings.xml is needed, in Linux (and MacOS) that's at ~/.m2/settings.xml + +As „servers“, enter the following +```xml +   +    +      github +      GITHUB-TOKEN +    +   +``` +The whole settings.xml then looks e.g. like this +```xml + + + + + + + + +      github +      TOKEN +     + + + + + + +``` + +The password is generated on github. +See the following screenshot: + + +Sign in in GitHub and click on the profile picture -> Settings. Now just generate a new token and set the checkboxes from the screenshot. +![screenshot](development_documentation_screenshot_github_settings.png "Screenshot Github Settings") + The Token-ID is the password. + + +## Release + +You will need a git client on the console, if that's available can e.g. be checked with "git --version" . +Change to the root of the repo. + +Change to the project directory and run + * "/usr/local/Cellar/maven/3.5.2/bin/mvn clean install" . If that works you can + * clean the release with „/usr/local/Cellar/maven/3.5.2/bin/mvn release:clean“ and prepare the release with + * "/usr/local/Cellar/maven/3.5.2/bin/mvn release:prepare -DignoreSnapshots=true" and enter the version numbers. + * After that is through you can create a new release via "/usr/local/Cellar/maven/3.5.2/bin/mvn release:perform -Darguments="-Dmaven.javadoc.skip=true".This will also update the maven repo. + + ![screenshot](development_documentation_screenshot_release.png "Screenshot Release") + + +Afterwards you can access the release page and update the documentation, e.g. upload the jar, the jar javadoc and ZugferdDev. You can also enter a changelog and a better title. + + +## Release process + + * Update documentation + * write/translate announcement + * release via/for mvn + * Publish a github release + * update mustangproject.org RE + * version number and release date + * sample file? + * Deployment jar + * put announcement on usegroup + * email the mailing list + * freshcode.club + \ No newline at end of file diff --git a/doc/development_documentation_screenshot_github_settings.png b/doc/development_documentation_screenshot_github_settings.png new file mode 100644 index 00000000..ff1ba41e Binary files /dev/null and b/doc/development_documentation_screenshot_github_settings.png differ diff --git a/doc/MustangDev.en.odt b/doc/development_documentation_screenshot_release.png similarity index 55% rename from doc/MustangDev.en.odt rename to doc/development_documentation_screenshot_release.png index b9b50a21..a7ea7074 100644 Binary files a/doc/MustangDev.en.odt and b/doc/development_documentation_screenshot_release.png differ diff --git a/pom.xml b/pom.xml index 650c1728..77463aa8 100644 --- a/pom.xml +++ b/pom.xml @@ -1,327 +1,341 @@ - - 4.0.0 - org.mustangproject.ZUGFeRD - mustang - 1.6.1-SNAPSHOT - jar - Mustang - The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs + + 4.0.0 + org.mustangproject.ZUGFeRD + mustang + 1.7.4-SNAPSHOT + jar + Mustang + The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs - http://www.mustangproject.org/ - - scm:git:https://github.com/ZUGFeRD/mustangproject.git - scm:git:https://github.com/ZUGFeRD/mustangproject.git - https://github.com/ZUGFeRD/mustangproject - mustang-1.5.2 - - - - sonatype-oss-public - https://oss.sonatype.org/content/groups/public/ - - true - - - true - - - - - - internal.repo - Temporary Staging Repository - file://${project.build.directory}/mvn-repo - - - - UTF-8 - github - -Xdoclint:none - - 1.8 - 1.8 - 1.8 - - - - - net.sf.saxon - Saxon-HE - 9.8.0-11 - - - com.sun.xml.bind - jaxb-impl - 2.2.11 - - - com.sun.xml.bind - jaxb-core - 2.2.11 - - - org.glassfish.jaxb - jaxb-runtime - 2.2.11 - - - org.apache.pdfbox - preflight - 2.0.12 - - - org.apache.pdfbox - pdfbox - 2.0.12 - - - junit - junit - 4.12 - test - - - com.helger - ph-schematron - 5.0.4 - test - - - org.xmlunit - xmlunit-core - 2.6.2 - test - - - - com.sanityinc - jargs - 2.0-SNAPSHOT - + http://www.mustangproject.org/ + + scm:git:https://github.com/ZUGFeRD/mustangproject.git + scm:git:https://github.com/ZUGFeRD/mustangproject.git + https://github.com/ZUGFeRD/mustangproject + mustang-1.7.3 + + + + sonatype-oss-public + https://oss.sonatype.org/content/groups/public/ + + true + + + true + + + + + + internal.repo + Temporary Staging Repository + file://${project.build.directory}/mvn-repo + + + + UTF-8 + github + -Xdoclint:none + + 1.8 + 1.8 + 1.8 + + + + + net.sf.saxon + Saxon-HE + 9.8.0-11 + + + com.sun.xml.bind + jaxb-impl + 2.2.11 + + + com.sun.xml.bind + jaxb-core + 2.2.11 + + + org.glassfish.jaxb + jaxb-runtime + 2.2.11 + + + javax.xml.bind + jaxb-api + 2.2.11 + + + javax.activation + activation + 1.1 + - - - - - + + com.sanityinc + jargs + 2.0-SNAPSHOT + + + + + + + - org.apache.maven.plugins - maven-release-plugin - 2.5.3 - - - - + org.apache.maven.plugins + maven-release-plugin + 2.5.3 + + + + - - - org.apache.maven.plugins - maven-compiler-plugin - 3.6.1 - - - - true - org.mustangproject.toecount.Toecount - - - - jar-with-dependencies - - - - 1.8 - 1.8 - - + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + + + true + org.mustangproject.toecount.Toecount + + + + jar-with-dependencies + + + + 1.8 + 1.8 + + - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.0.1 - + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.0.1 + - org.mustangproject.ZUGFeRD.model.* + org.mustangproject.ZUGFeRD.model.* - - - - maven-deploy-plugin - 2.8.2 - - internal.repo::default::file://${project.build.directory}/mvn-repo - - - - - com.github.github - site-maven-plugin - 0.12 - - Maven artifacts for ${project.version} - - true - - ${project.build.directory}/mvn-repo - - refs/heads/mvn-repo - - - **/* - - true - mustangproject - - ZUGFeRD - - - - - - - site - - deploy - - - - - org.apache.maven.plugins - maven-shade-plugin - 2.4.3 - - - - org.mustangproject.toecount.Toecount - - - true - + + + + maven-deploy-plugin + 2.8.2 + + internal.repo::default::file://${project.build.directory}/mvn-repo + + + + + com.github.github + site-maven-plugin + 0.12 + + Maven artifacts for ${project.version} + + true + + ${project.build.directory}/mvn-repo + + refs/heads/mvn-repo + + + **/* + + true + mustangproject + + ZUGFeRD + + + + + + + site + + deploy + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.3 + + + + org.mustangproject.toecount.Toecount + + + true + - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - - log4j:log4j - - ** - - - - commons-logging:commons-logging - - ** - - - - com.sun.xml.bind:jaxb-impl - - ** - - - - com.sun.xml.bind:jaxb-core - - ** - - - - - - - package - - shade - - - - - - - - - - - - - org.codehaus.mojo - templating-maven-plugin - 1.0.0 - - - filtering-java-templates - - filter-sources - - - - - - org.codehaus.mojo - jaxb2-maven-plugin - 2.3.1 - - - xjc - - xjc - - - - - 2.1 - org.mustangproject.ZUGFeRD.model - - src/main/resources/schema/ZUGFeRD1p0.xsd - - - - - - - - User List - https://groups.google.com/forum/?hl=de#!forum/mustangproject - - - - - Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - A business-friendly OSS license - - - - - Jochen Stärk - jstaerk@usegroup.de - - architect - developer - - - - Alexander Schmidt - schmidt.alexander@mail.de - - developer - - - + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + log4j:log4j + + ** + + + + commons-logging:commons-logging + + ** + + + + com.sun.xml.bind:jaxb-impl + + ** + + + + com.sun.xml.bind:jaxb-core + + ** + + + + + + + package + + shade + + + + + + + + + + + + + org.codehaus.mojo + templating-maven-plugin + 1.0.0 + + + filtering-java-templates + + filter-sources + + + + + + org.codehaus.mojo + jaxb2-maven-plugin + 2.5.0 + + + xjc + + xjc + + + + + 2.1 + org.mustangproject.ZUGFeRD.model + + src/main/resources/schema/ZUGFeRD1p0.xsd + + + + + + + + User List + https://groups.google.com/forum/?hl=de#!forum/mustangproject + + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + A business-friendly OSS license + + + + + Jochen Stärk + jstaerk@usegroup.de + + architect + developer + + + + Alexander Schmidt + schmidt.alexander@mail.de + + developer + + + diff --git a/src/main/java/org/mustangproject/ZUGFeRD/CustomXMLProvider.java b/src/main/java/org/mustangproject/ZUGFeRD/CustomXMLProvider.java index dfd8be88..6ac2c275 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/CustomXMLProvider.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/CustomXMLProvider.java @@ -18,7 +18,7 @@ *********************************************************************** */ package org.mustangproject.ZUGFeRD; -public class CustomXMLProvider implements IXMLProvider { +public class CustomXMLProvider implements IXMLProvider, IProfileProvider { protected byte[] zugferdData; @@ -48,4 +48,14 @@ public class CustomXMLProvider implements IXMLProvider { } + @Override + public String getProfile() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setProfile(ZUGFeRDConformanceLevel level) { + // TODO Auto-generated method stub + } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/IExporterFactory.java b/src/main/java/org/mustangproject/ZUGFeRD/IExporterFactory.java index 47c22cc6..6822d744 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/IExporterFactory.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/IExporterFactory.java @@ -22,6 +22,13 @@ import java.io.IOException; import java.io.InputStream; public interface IExporterFactory { + /** + * factory: loads a PDF file and returns an appropriate exporter + * + * @param pdfFilename binary of a PDF/A1 compliant document + * @return the generated exporter + * @throws IOException if anything is wrong with filename + */ public ZUGFeRDExporter load(String pdfFilename) throws IOException; /** @@ -29,6 +36,8 @@ public interface IExporterFactory { * metadata level, this will not e.g. convert graphics to JPG-2000) * * @param pdfBinary binary of a PDF/A1 compliant document + * @return the generated exporter + * @throws IOException (should not happen at all) */ public ZUGFeRDExporter load(byte[] pdfBinary) throws IOException; @@ -37,7 +46,8 @@ public interface IExporterFactory { * metadata level, this will not e.g. convert graphics to JPG-2000) * * @param pdfSource source to read a PDF/A1 compliant document from - * @throws IOException + * @throws IOException if anything is wrong with inputstream + * @return the generated ZUGFeRDExporter */ public ZUGFeRDExporter load(InputStream pdfSource) throws IOException; diff --git a/src/main/java/org/mustangproject/ZUGFeRD/IProfileProvider.java b/src/main/java/org/mustangproject/ZUGFeRD/IProfileProvider.java new file mode 100644 index 00000000..d4469edb --- /dev/null +++ b/src/main/java/org/mustangproject/ZUGFeRD/IProfileProvider.java @@ -0,0 +1,27 @@ +/** ********************************************************************** + * + * Copyright 2018 Jochen Staerk + * + * Use is subject to license terms. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ +package org.mustangproject.ZUGFeRD; + +public interface IProfileProvider { + + public String getProfile(); + + public void setProfile(ZUGFeRDConformanceLevel level); + +} diff --git a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java index a1de8dd2..289fa0c9 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java @@ -19,11 +19,11 @@ package org.mustangproject.ZUGFeRD; /** - * Mustangproject's ZUGFeRD implementation Neccessary interface for ZUGFeRD exporter Licensed under the APLv2 + * Mustangproject's ZUGFeRD implementation neccessary interface for ZUGFeRD exporter Licensed under the APLv2 * * @author jstaerk * @version 1.2.0 - * @date 2014-05-10 + * dated 2014-05-10 */ @@ -38,6 +38,24 @@ public interface IZUGFeRDExportableContact { return null; } + /** + * customer global identification assigned by the seller + * + * @return customer identification + */ + default String getGlobalID() { + return null; + } + + /** + * customer global identification scheme + * + * @return customer identification + */ + default String getGlobalIDScheme() { + return null; + } + /** * First and last name of the recipient @@ -48,6 +66,14 @@ public interface IZUGFeRDExportableContact { return null; } + default String getPhone() { + return null; + } + + default String getEMail() { + return null; + } + /** * Postal code of the recipient diff --git a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java index d58a2588..ea41877f 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableProduct.java @@ -27,7 +27,7 @@ import java.math.BigDecimal; * * @author jstaerk * @version 1.2.0 - * @date 2014-05-10 + * dated 2014-05-10 */ public interface IZUGFeRDExportableProduct { diff --git a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java index fd1308ef..20b18006 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java @@ -27,12 +27,21 @@ package org.mustangproject.ZUGFeRD; * */ -import java.util.Date; +import java.math.BigDecimal; +import java.util.Date; import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants; public interface IZUGFeRDExportableTransaction { + /** + * appears in /rsm:CrossIndustryDocument/rsm:HeaderExchangedDocument/ram:Name + * @return Name of document + */ + default String getDocumentName() { + return "RECHNUNG"; + } + /** * * @@ -65,7 +74,7 @@ public interface IZUGFeRDExportableTransaction { /** * this should be the full sender institution name, details, manager and tax registration. It is one of the few functions which may return null. e.g. - *

+ *

* Lieferant GmbH Lieferantenstraße 20 80333 München Deutschland Geschäftsführer: Hans Muster Handelsregisternummer: H A 123 * * @return null or full sender institution name, details, manager and tax registration @@ -84,6 +93,15 @@ public interface IZUGFeRDExportableTransaction { return null; } + /** + * who processed the order + * + * @return the contact person at the supplier side + */ + default IZUGFeRDExportableContact getOwnContact() { + return null; + } + IZUGFeRDAllowanceCharge[] getZFAllowances(); @@ -106,53 +124,11 @@ public interface IZUGFeRDExportableTransaction { /** - * BIC of the sender - * - * @return the BIC code of the recipient sender's bank + * the creditors payment informations + * + * @return an array of IZUGFeRDTradeSettlementPayment */ - default String getOwnBIC() { - return null; - } - - - /** - * BLZ of the sender - * - * @return the BLZ code of the recipient sender's bank - */ - default String getOwnBLZ() { - return null; - } - - - /** - * Bank name of the sender - * - * @return the name of the sender's bank - */ - default String getOwnBankName() { - return null; - } - - - /** - * IBAN of the sender - * - * @return the IBAN of the invoice sender's bank account - */ - default String getOwnIBAN() { - return null; - } - - - /** - * IBAN of the sender - * - * @return the Account Number of the invoice sender's bank account - */ - default String getOwnKto() { - return null; - } + IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment(); /** @@ -253,16 +229,6 @@ public interface IZUGFeRDExportableTransaction { } - /** - * get payment information text. e.g. Bank transfer - * - * @return payment information text - */ - default String getOwnPaymentInfoText() { - return null; - } - - /** * get payment term descriptional text e.g. Bis zum 22.10.2015 ohne Abzug * @@ -282,7 +248,6 @@ public interface IZUGFeRDExportableTransaction { return null; } - /** * get reference number of the purchase order this invoice is based on * @@ -352,4 +317,23 @@ public interface IZUGFeRDExportableTransaction { return null; } + /** + * get the ID of the BuyerOrderReferencedDocument, which sits in the ApplicableSupplyChainTradeAgreement + * @return the ID of the document + */ + default String getBuyerOrderReferencedDocumentID() { return null; } + + /** + * get the issue timestamp of the BuyerOrderReferencedDocument, which sits in the ApplicableSupplyChainTradeAgreement + * @return the IssueDateTime in format CCYY-MM-DDTHH:MM:SS + */ + default String getBuyerOrderReferencedDocumentIssueDateTime() { return null; } + + /** + * get the TotalPrepaidAmount located in SpecifiedTradeSettlementMonetarySummation (v1) or + * SpecifiedTradeSettlementHeaderMonetarySummation (v2) + * @return the total sum (incl. VAT) of prepayments, i.e. the difference between GrandTotalAmount + * and DuePayableAmount + */ + default BigDecimal getTotalPrepaidAmount() { return BigDecimal.ZERO; } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPayment.java b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPayment.java new file mode 100644 index 00000000..3b45b9c8 --- /dev/null +++ b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPayment.java @@ -0,0 +1,81 @@ +/** ********************************************************************** + * + * Copyright 2019 by ak on 12.04.19. + * + * Use is subject to license terms. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ +package org.mustangproject.ZUGFeRD; + +public interface IZUGFeRDTradeSettlementPayment { + + /** + * get payment information text. e.g. Bank transfer + * + * @return payment information text + */ + default String getOwnPaymentInfoText() { + return null; + } + + /** + * BIC of the sender + * + * @return the BIC code of the recipient sender's bank + */ + default String getOwnBIC() { + return null; + } + + + /** + * BLZ of the sender + * + * @return the BLZ code of the recipient sender's bank + */ + default String getOwnBLZ() { + return null; + } + + + /** + * Bank name of the sender + * + * @return the name of the sender's bank + */ + default String getOwnBankName() { + return null; + } + + + /** + * IBAN of the sender + * + * @return the IBAN of the invoice sender's bank account + */ + default String getOwnIBAN() { + return null; + } + + + /** + * IBAN of the sender + * + * @return the Account Number of the invoice sender's bank account + */ + default String getOwnKto() { + return null; + } + +} diff --git a/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java b/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java index 408ea69f..3ba0acc1 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/VATAmount.java @@ -27,20 +27,20 @@ import java.math.BigDecimal; * * @author jstaerk * @version 1.2.0 - * @date 2015-10-29 + * dated 2015-10-29 */ public class VATAmount { - public VATAmount(BigDecimal basis, BigDecimal calculated, String documentCode) { + public VATAmount(BigDecimal basis, BigDecimal calculated, String categoryCode) { super(); this.basis = basis; this.calculated = calculated; - this.documentCode = documentCode; + this.categoryCode = categoryCode; } BigDecimal basis, calculated; - String documentCode; + String categoryCode; public BigDecimal getBasis() { return basis; @@ -58,20 +58,39 @@ public class VATAmount { this.calculated = calculated; } + /** + * + * @deprecated Use {@link #getCategoryCode() instead} + * @return String with category code + */ + @Deprecated public String getDocumentCode() { - return documentCode; + return categoryCode; } + /** + * @param documentCode as String + * @deprecated Use {@link #setCategoryCode(String)} instead + */ + @Deprecated public void setDocumentCode(String documentCode) { - this.documentCode = documentCode; + this.categoryCode = documentCode; + } + + public String getCategoryCode() { + return categoryCode; + } + + public void setCategoryCode(String categoryCode) { + this.categoryCode = categoryCode; } public VATAmount add(VATAmount v) { - return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.documentCode); + return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode); } public VATAmount subtract(VATAmount v) { - return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.documentCode); + return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.categoryCode); } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java b/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java index 131638db..3e0dca57 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaPDFAExtensions.java @@ -52,11 +52,13 @@ public class XMPSchemaPDFAExtensions extends PDFAExtensionSchema { public final String prefix_pdfaProperty = "pdfaProperty"; public String namespace = null; public String prefix = null; + + protected ZUGFeRDExporter exporter; protected void setZUGFeRDVersion(int ver) { - namespace = ZUGFeRDExporter.getNamespaceForVersion(ver); - prefix = ZUGFeRDExporter.getPrefixForVersion(ver); + namespace = exporter.getNamespaceForVersion(ver); + prefix = exporter.getPrefixForVersion(ver); } @@ -87,14 +89,16 @@ public class XMPSchemaPDFAExtensions extends PDFAExtensionSchema { return li; } - public XMPSchemaPDFAExtensions(XMPMetadata metadata, int ZFVersion) { + public XMPSchemaPDFAExtensions(ZUGFeRDExporter ze, XMPMetadata metadata, int ZFVersion) { super(metadata); + exporter=ze; setZUGFeRDVersion(ZFVersion); attachExtensions(metadata, true); } - public XMPSchemaPDFAExtensions(XMPMetadata metadata, int ZFVersion, boolean withZF) { + public XMPSchemaPDFAExtensions(ZUGFeRDExporter ze, XMPMetadata metadata, int ZFVersion, boolean withZF) { super(metadata); + exporter=ze; setZUGFeRDVersion(ZFVersion); attachExtensions(metadata, withZF); } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java b/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java index 57cc5197..c2a4bde5 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/XMPSchemaZugferd.java @@ -31,8 +31,13 @@ import org.apache.xmpbox.schema.XMPSchema; public class XMPSchemaZugferd extends XMPSchema { - /** + /*** * This is what needs to be added to the RDF metadata - basically the name of the embedded Zugferd file + * @param metadata the xmp to be added to + * @param conformanceLevel e.g. conformanceLevel.EN16931 + * @param URN the xml URI for the XMP + * @param prefix the xml namespace prefix for the XMP, zf for ZUGFeRD, fx for Factur-X + * @param filename the filename of the invoice */ public XMPSchemaZugferd(XMPMetadata metadata, ZUGFeRDConformanceLevel conformanceLevel, String URN, String prefix, String filename) { super(metadata, URN, prefix, "ZUGFeRD Schema"); diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java index 3c782866..f8278a32 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java @@ -19,6 +19,7 @@ package org.mustangproject.ZUGFeRD; import org.mustangproject.ZUGFeRD.model.CrossIndustryDocumentType; +import org.mustangproject.ZUGFeRD.model.DocumentContextParameterTypeConstants; import org.mustangproject.ZUGFeRD.model.ZFNamespacePrefixMapper; import javax.xml.bind.JAXBContext; @@ -27,13 +28,27 @@ import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import java.io.ByteArrayOutputStream; -public class ZUGFeRD1PullProvider implements IXMLProvider { +public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider { protected byte[] zugferdData; private Marshaller marshaller; private boolean isTest; + private ZUGFeRDConformanceLevel level; + + + public void setProfile(ZUGFeRDConformanceLevel level) { + this.level = level; + } + + public String getProfile() { + switch (level) { + case BASIC: return DocumentContextParameterTypeConstants.BASIC; + case COMFORT: return DocumentContextParameterTypeConstants.COMFORT; + default: return DocumentContextParameterTypeConstants.EXTENDED; + } + } /** @@ -59,7 +74,7 @@ public class ZUGFeRD1PullProvider implements IXMLProvider { private String createZugferdXMLForTransaction(IZUGFeRDExportableTransaction trans) { JAXBElement jaxElement = - new ZUGFeRDTransactionModelConverter(trans).withTest(isTest).convertToModel(); + new ZUGFeRDTransactionModelConverter(trans).withTest(isTest).withProfile(getProfile()).convertToModel(); try { return marshalJaxToXMLString(jaxElement); diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 52a77fe5..bd8a70ff 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -18,28 +18,42 @@ *********************************************************************** */ package org.mustangproject.ZUGFeRD; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; +import java.math.RoundingMode; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.HashMap; +import java.util.logging.Level; +import java.util.logging.Logger; -public class ZUGFeRD2PullProvider implements IXMLProvider { +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.XMLWriter; +import org.mustangproject.toecount.Toecount; + +public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { private class LineCalc { - private IZUGFeRDExportableItem currentItem = null; private BigDecimal totalGross; private BigDecimal itemTotalNetAmount; private BigDecimal itemTotalVATAmount; public LineCalc(IZUGFeRDExportableItem currentItem) { - this.currentItem = currentItem; - BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100)).add(new BigDecimal(1)); -// priceGross=currentItem.getPrice().multiply(multiplicator); + BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100)) + .add(new BigDecimal(1)); + // priceGross=currentItem.getPrice().multiply(multiplicator); totalGross = currentItem.getPrice().multiply(multiplicator).multiply(currentItem.getQuantity()); - itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).setScale(2, BigDecimal.ROUND_HALF_UP); + itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).setScale(2, + BigDecimal.ROUND_HALF_UP); itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount); } @@ -53,77 +67,90 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { } - //// MAIN CLASS protected byte[] zugferdData; private IZUGFeRDExportableTransaction trans; - private boolean isTest; + private ZUGFeRDConformanceLevel level; + + public void setProfile(ZUGFeRDConformanceLevel level) { + this.level = level; + } /** * enables the flag to indicate a test invoice in the XML structure */ public void setTest() { - isTest = true; } - private String nDigitFormat(BigDecimal value, int scale) { + public static String nDigitFormat(BigDecimal value, int scale) { /* * I needed 123,45, locale independent.I tried - * NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is - * locale specific.I also tried DecimalFormat df = new DecimalFormat( - * "0,00" ); df.setDecimalSeparatorAlwaysShown(true); - * df.setGroupingUsed(false); DecimalFormatSymbols symbols = new - * DecimalFormatSymbols(); symbols.setDecimalSeparator(','); - * symbols.setGroupingSeparator(' '); + * NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is locale + * specific.I also tried DecimalFormat df = new DecimalFormat( "0,00" ); + * df.setDecimalSeparatorAlwaysShown(true); df.setGroupingUsed(false); + * DecimalFormatSymbols symbols = new DecimalFormatSymbols(); + * symbols.setDecimalSeparator(','); symbols.setGroupingSeparator(' '); * df.setDecimalFormatSymbols(symbols); * - * but that would not switch off grouping. Although I liked very much - * the (incomplete) "BNF diagram" in - * http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html - * in the end I decided to calculate myself and take eur+sparator+cents + * but that would not switch off grouping. Although I liked very much the + * (incomplete) "BNF diagram" in + * http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html in the + * end I decided to calculate myself and take eur+sparator+cents * - * This function will cut off, i.e. floor() subcent values Tests: - * System.err.println(utils.currencyFormat(new BigDecimal(0), - * ".")+"\n"+utils.currencyFormat(new BigDecimal("-1.10"), - * ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.1"), - * ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.01"), - * ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3489"), - * ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3419"), - * ",")+"\n"+utils.currencyFormat(new BigDecimal("12"), ",")); - * - * results 0.00 -1,10 -1,10 -1,01 20000123,34 20000123,34 12,00 */ - value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); // first, round so that e.g. 1.189999999999999946709294817992486059665679931640625 becomes 1.19 - char[] repeat = new char[scale]; - Arrays.fill(repeat, '0'); - - DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(); - otherSymbols.setDecimalSeparator('.'); - DecimalFormat dec = new DecimalFormat("0." + new String(repeat), otherSymbols); - return dec.format(value); + return value.setScale(scale, RoundingMode.HALF_UP).toPlainString(); } private String vatFormat(BigDecimal value) { - return nDigitFormat(value, 2); + return ZUGFeRD2PullProvider.nDigitFormat(value, 2); } private String currencyFormat(BigDecimal value) { - return nDigitFormat(value, 2); + return ZUGFeRD2PullProvider.nDigitFormat(value, 2); } private String priceFormat(BigDecimal value) { - return nDigitFormat(value, 4); + return ZUGFeRD2PullProvider.nDigitFormat(value, 4); } private String quantityFormat(BigDecimal value) { - return nDigitFormat(value, 4); + return ZUGFeRD2PullProvider.nDigitFormat(value, 4); } @Override public byte[] getXML() { - return zugferdData; + + byte[] res = zugferdData; + + StringWriter sw = new StringWriter(); + Document document=null; + try { + document = DocumentHelper.parseText(new String(zugferdData)); + } catch (DocumentException e1) { + Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e1); + } + try { + OutputFormat format = OutputFormat.createPrettyPrint(); + XMLWriter writer = new XMLWriter(sw, format); + writer.write(document); + res = sw.toString().getBytes("UTF-8"); + + } catch (IOException e) { + Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e); + } + + return res; + + } + + private BigDecimal getTotalPrepaid() { + if (trans.getTotalPrepaidAmount()==null) { + return new BigDecimal(0); + } else { + return trans.getTotalPrepaidAmount(); + } } private BigDecimal getTotalGross() { @@ -147,20 +174,20 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { } /** - * which taxes have been used with which amounts in this transaction, - * empty for no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable - * to 19% VAT (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT) - * 190 Eur + * which taxes have been used with which amounts in this transaction, empty for + * no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable to 19% VAT + * (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT) 190 Eur * * @return which taxes have been used with which amounts in this invoice */ private HashMap getVATPercentAmountMap() { - HashMap hm = new HashMap(); + HashMap hm = new HashMap<>(); for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { BigDecimal percent = currentItem.getProduct().getVATPercent(); LineCalc lc = new LineCalc(currentItem); - VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), trans.getDocumentCode()); + VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), + trans.getDocumentCode()); VATAmount current = hm.get(percent); if (current == null) { hm.put(percent, itemVATAmount); @@ -171,61 +198,101 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { return hm; } + public String getProfile() { + return "urn:cen.eu:en16931:2017"; + } + + public static String encodeXML(CharSequence s) { + StringBuilder sb = new StringBuilder(); + int len = s.length(); + for (int i=0;i= 0xd800 && c <= 0xdbff && i + 1 < len) { + c = ((c-0xd7c0)<<10) | (s.charAt(++i)&0x3ff); // UTF16 decode + } + if (c < 0x80) { // ASCII range: test most common case first + if (c < 0x20 && (c != '\t' && c != '\r' && c != '\n')) { + // Illegal XML character, even encoded. Skip or substitute + sb.append("�"); // Unicode replacement character + } else { + switch(c) { + case '&': sb.append("&"); break; + case '>': sb.append(">"); break; + case '<': sb.append("<"); break; + // Uncomment next two if encoding for an XML attribute +// case '\'' sb.append("'"); break; +// case '\"' sb.append("""); break; + // Uncomment next three if you prefer, but not required +// case '\n' sb.append(" "); break; +// case '\r' sb.append(" "); break; +// case '\t' sb.append(" "); break; + + default: sb.append((char)c); + } + } + } else if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) { + // Illegal XML character, even encoded. Skip or substitute + sb.append("�"); // Unicode replacement character + } else { + sb.append("&#x"); + sb.append(Integer.toHexString(c)); + sb.append(';'); + } + } + return sb.toString(); + } @Override public void generateXML(IZUGFeRDExportableTransaction trans) { - this.trans = trans; SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); //$NON-NLS-1$ SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); //$NON-NLS-1$ - String testBooleanStr = "false"; - if (isTest) { - testBooleanStr = "true"; - - } String senderReg = ""; if (trans.getOwnOrganisationFullPlaintextInfo() != null) { - senderReg = "" - + "\n" - + " \n" - + trans.getOwnOrganisationFullPlaintextInfo() - + " \n" - + "REG\n" - + "\n"; + senderReg = "" + "\n" + " \n" + + encodeXML(trans.getOwnOrganisationFullPlaintextInfo()) + " \n" + + "REG\n" + "\n"; } - String xml = "\n" //$NON-NLS-1$ + "\n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ -// + " "+testBooleanStr+"\n" //$NON-NLS-1$ + // + " + // "+testBooleanStr+"\n" + // //$NON-NLS-1$ + " \n" //$NON-NLS-1$ - + " urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931\n" //$NON-NLS-1$ + + " " + getProfile() + "\n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ - + " " + trans.getNumber() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ -// + " RECHNUNG\n" //$NON-NLS-1$ + + " " + encodeXML(trans.getNumber()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + // + " RECHNUNG\n" //$NON-NLS-1$ + " 380\n" //$NON-NLS-1$ - + " " + zugferdDateFormat.format(trans.getIssueDate()) + "\n" //date format was 20130605 //$NON-NLS-1$ //$NON-NLS-2$ + + " " //$NON-NLS-1$ + + zugferdDateFormat.format(trans.getIssueDate()) + "\n" // date //$NON-NLS-1$ + // format + // was + // 20130605 + senderReg -// + " \n" -// + " \n" -// + "Rechnung gemäß Bestellung Nr. 2013-471331 vom 01.03.2013.\n" -// + "\n" -// + " \n" -// + " \n" -// + " \n" -// + " \n" -// + "Es bestehen Rabatt- und Bonusvereinbarungen.\n" -// + " \n" -// + " AAK\n" -// + " \n" + // + " \n" + // + " \n" + // + "Rechnung gemäß Bestellung Nr. 2013-471331 vom 01.03.2013.\n" + // + "\n" + // + " \n" + // + " \n" + // + " \n" + // + " \n" + // + "Es bestehen Rabatt- und Bonusvereinbarungen.\n" + // + " \n" + // + " AAK\n" + // + " \n" + " \n" //$NON-NLS-1$ + " \n"; //$NON-NLS-1$ int lineID = 0; @@ -238,188 +305,243 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { + " " + lineID + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ -// + " 4012345001235\n" -// + " KR3M\n" -// + " 55T01\n" - + " " + currentItem.getProduct().getName() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " " + currentItem.getProduct().getDescription() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + // + " 4012345001235\n" + // + " KR3M\n" + // + " 55T01\n" + + " " + encodeXML(currentItem.getProduct().getName()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + encodeXML(currentItem.getProduct().getDescription()) //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ - + " " + priceFormat(currentItem.getPrice()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ //currencyID=\"EUR\" - + " 1.0000\n" //$NON-NLS-1$ //$NON-NLS-2$ -// + " \n" -// + " false\n" -// + " 0.6667\n" -// + " Rabatt\n" -// + " \n" + + " " + priceFormat(currentItem.getPrice()) //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ //currencyID=\"EUR\" + + " 1.0000\n" //$NON-NLS-1$ + // + " \n" + // + " false\n" + // + " 0.6667\n" + // + " Rabatt\n" + // + " \n" + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ - + " " + priceFormat(currentItem.getPrice()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" - + " 1.0000\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + priceFormat(currentItem.getPrice()) //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ // currencyID=\"EUR\" + + " 1.0000\n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ - + " " + quantityFormat(currentItem.getQuantity()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + " " //$NON-NLS-1$ //$NON-NLS-2$ + + quantityFormat(currentItem.getQuantity()) + "\n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " VAT\n" //$NON-NLS-1$ + " S\n" //$NON-NLS-1$ - + " " + vatFormat(currentItem.getProduct().getVATPercent()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " //$NON-NLS-1$ + + vatFormat(currentItem.getProduct().getVATPercent()) + "\n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ - + " " + currencyFormat(lc.getItemTotalNetAmount()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" + + " " + currencyFormat(lc.getItemTotalNetAmount()) //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ // currencyID=\"EUR\" + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n"; //$NON-NLS-1$ + } + + xml = xml + " \n"; //$NON-NLS-1$ + if (trans.getReferenceNumber() != null) { + xml = xml + " " + encodeXML(trans.getReferenceNumber()) + "\n"; + + } + xml = xml + " \n" //$NON-NLS-1$ + // + " 4000001123452\n" + + " " + encodeXML(trans.getOwnOrganisationName()) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + + if ((trans.getOwnVATID()!=null)&&(trans.getOwnOrganisationName()!=null)) { + + xml = xml + " \n" + " " + + encodeXML(trans.getOwnVATID()) + "\n" + " " + + encodeXML(trans.getOwnOrganisationName()) + "\n" + + " "; + } + + if (trans.getOwnContact() != null) { + xml = xml + "\n" + " " + encodeXML(trans.getOwnContact().getName()) + + "\n"; + if (trans.getOwnContact().getPhone() != null) { + + xml = xml + " \n" + " " + + encodeXML(trans.getOwnContact().getPhone()) + "\n" + + " \n"; + } + if (trans.getOwnContact().getEMail() != null) { + + xml = xml + " \n" + " " + + encodeXML(trans.getOwnContact().getEMail()) + "\n" + + " \n"; + } + xml = xml + " "; } - xml = xml + " \n" //$NON-NLS-1$ -// + " AB-312\n" - + " \n" //$NON-NLS-1$ -// + " 4000001123452\n" - + " " + trans.getOwnOrganisationName() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" - + " " + trans.getOwnZIP() + "\n" - + " " + trans.getOwnStreet() + "\n" - + " " + trans.getOwnLocation() + "\n" - + " " + trans.getOwnCountry() + "\n" - + " \n" + xml = xml + " \n" + " " + + encodeXML(trans.getOwnZIP()) + "\n" + " " + + encodeXML(trans.getOwnStreet()) + "\n" + " " + encodeXML(trans.getOwnLocation()) + + "\n" + " " + encodeXML(trans.getOwnCountry()) + + "\n" + " \n" + " \n" //$NON-NLS-1$ - + " " + trans.getOwnTaxID() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + encodeXML(trans.getOwnTaxID()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ - + " " + trans.getOwnVATID() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + encodeXML(trans.getOwnVATID()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ -// + " GE2020211\n" -// + " 4000001987658\n" - + " " + trans.getRecipient().getName() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ -// + " \n" -// + " xxx\n" -// + " \n" + // + " GE2020211\n" + // + " 4000001987658\n" + + " " + encodeXML(trans.getRecipient().getName()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + // + " \n" + // + " xxx\n" + // + " \n" + " \n" //$NON-NLS-1$ - + " " + trans.getRecipient().getZIP() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " " + trans.getRecipient().getStreet() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " " + trans.getRecipient().getLocation() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " " + trans.getRecipient().getCountry() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " " + trans.getRecipient().getVATID() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ -// + " \n" -// + " 20130301\n" -// + " 2013-471331\n" -// + " \n" + + " " + encodeXML(trans.getRecipient().getZIP()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + encodeXML(trans.getRecipient().getStreet()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + encodeXML(trans.getRecipient().getLocation()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + encodeXML(trans.getRecipient().getCountry()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n"; //$NON-NLS-1$ + if (trans.getRecipient().getVATID() != null) { + xml += " \n" //$NON-NLS-1$ + + " " + encodeXML(trans.getRecipient().getVATID()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " \n"; //$NON-NLS-1$ + } + xml += " \n" //$NON-NLS-1$ + // + " \n" + // + " 20130301\n" + // + " 2013-471331\n" + // + " \n" + " \n" //$NON-NLS-1$ - + " \n" - + " \n" - + " " + zugferdDateFormat.format(trans.getDeliveryDate()) + "\n" + + " \n" + " \n" + + " " + + zugferdDateFormat.format(trans.getDeliveryDate()) + "\n" + " \n" - /* - + " \n" - + " 20130603\n" - + " 2013-51112\n" - + " \n" */ - + " \n" - + " \n" //$NON-NLS-1$ - + " " + trans.getNumber() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " EUR\n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " 42\n" //$NON-NLS-1$ - + " Überweisung\n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " " + trans.getOwnIBAN() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " " + trans.getOwnKto() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n" //$NON-NLS-1$ - + " " + trans.getOwnBIC() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " " + trans.getOwnBLZ() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ -// + " "+trans.getOwnBankName()+"\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " \n" //$NON-NLS-1$ - + " \n"; //$NON-NLS-1$ + /* + * + " \n" + + * " 20130603\n" + + * " 2013-51112\n" + + * " \n" + */ + + " \n" + " \n" //$NON-NLS-2$ + + " " + encodeXML(trans.getNumber()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " EUR\n"; //$NON-NLS-1$ + for (IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) { + xml += " \n" //$NON-NLS-1$ + + " 42\n" //$NON-NLS-1$ + + " Überweisung\n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + encodeXML(payment.getOwnIBAN()) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + if (payment.getOwnKto()!=null) { + xml+= " " + encodeXML(payment.getOwnKto()) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + + } + xml+= " \n" //$NON-NLS-1$ + + " \n" //$NON-NLS-1$ + + " " + encodeXML(payment.getOwnBIC()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + // + " "+trans.getOwnBankName()+"\n" //$NON-NLS-1$ + // //$NON-NLS-2$ + + " \n" //$NON-NLS-1$ + + " \n"; //$NON-NLS-1$ + } HashMap VATPercentAmountMap = getVATPercentAmountMap(); for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) { VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); if (amount != null) { xml += " \n" //$NON-NLS-1$ - + " " + currencyFormat(amount.getCalculated()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ //currencyID=\"EUR\" + + " " + currencyFormat(amount.getCalculated()) //$NON-NLS-1$ + + "\n" //$NON-NLS-1$ //currencyID=\"EUR\" + " VAT\n" //$NON-NLS-1$ + " " + currencyFormat(amount.getBasis()) + "\n" // currencyID=\"EUR\" + " S\n" //$NON-NLS-1$ - + " " + vatFormat(currentTaxPercent) + "\n" //$NON-NLS-1$ - + " \n"; //$NON-NLS-1$ - + + " " + vatFormat(currentTaxPercent) //$NON-NLS-1$ + + "\n" + " \n"; //$NON-NLS-2$ } } - /* xml+= " - + " \n" - + " false\n" - + " 10\n" - + " 1.00\n" - + " Sondernachlass\n" - + " \n" - + " VAT\n" - + " S\n" - + " 19\n" - + " \n" - + " \n" - + " \n" - + " false\n" - + " 137.30\n" - + " 13.73\n" - + " Sondernachlass\n" - + " \n" - + " VAT\n" - + " S\n" - + " 7\n" - + " \n" - + " \n" - + " \n" - + " Versandkosten\n" - + " 5.80\n" - + " \n" - + " VAT\n" - + " S\n" - + " 7\n" - + " \n" - + " \n"*/ + /* + * xml+= " + " \n" + + * " false\n" + + * " 10\n" + + * " 1.00\n" + + * " Sondernachlass\n" + + * " \n" + + * " VAT\n" + + * " S\n" + + * " 19\n" + + * " \n" + + * " \n" + + * " \n" + + * " false\n" + + * " 137.30\n" + + * " 13.73\n" + + * " Sondernachlass\n" + + * " \n" + + * " VAT\n" + + * " S\n" + + * " 7\n" + + * " \n" + + * " \n" + + * " \n" + + * " Versandkosten\n" + + * " 5.80\n" + + * " \n" + + * " VAT\n" + + * " S\n" + + * " 7\n" + + * " \n" + + * " \n" + */ xml = xml + " \n" //$NON-NLS-1$ - + " Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate()) + "\n" - + " " + zugferdDateFormat.format(trans.getDueDate()) + "\n"//20130704 //$NON-NLS-1$ //$NON-NLS-2$ + + " Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate()) + + "\n" + " " //$NON-NLS-2$ + + zugferdDateFormat.format(trans.getDueDate()) + "\n"// 20130704 //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ - + " " + currencyFormat(getTotal()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ currencyID=\"EUR\" - + " 0.00\n" //$NON-NLS-1$ currencyID=\"EUR\" - + " 0.00\n" //$NON-NLS-1$ // currencyID=\"EUR\" -// + " 5.80\n" -// + " 14.73\n" - + " " + currencyFormat(getTotal()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" - + " " + currencyFormat(getTotalGross().subtract(getTotal())) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " " + currencyFormat(getTotalGross()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" -// + " 0.00\n" - + " " + currencyFormat(getTotalGross()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\" + + " " + currencyFormat(getTotal()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + // currencyID=\"EUR\" + + " 0.00\n" //$NON-NLS-1$ currencyID=\"EUR\" + + " 0.00\n" //$NON-NLS-1$ // + // currencyID=\"EUR\" + // + " 5.80\n" + // + " 14.73\n" + + " " + currencyFormat(getTotal()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + // // + // currencyID=\"EUR\" + + " " //$NON-NLS-1$ + + currencyFormat(getTotalGross().subtract(getTotal())) + "\n" //$NON-NLS-1$ + + " " + currencyFormat(getTotalGross()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + // // + // currencyID=\"EUR\" + + " " + currencyFormat(getTotalPrepaid()) + "\n" + + " " + currencyFormat(getTotalGross().subtract(getTotalPrepaid())) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + // // + // currencyID=\"EUR\" + " \n" //$NON-NLS-1$ + " \n"; //$NON-NLS-1$ -// + " \n" -// + " \n" -// + " \n" -// + " Wir erlauben uns Ihnen folgende Positionen aus der Lieferung Nr. 2013-51112 in Rechnung zu stellen:\n" -// + " \n" -// + " \n" -// + " \n"; - + // + " \n" + // + " \n" + // + " \n" + // + " Wir erlauben uns Ihnen folgende Positionen aus der Lieferung Nr. + // 2013-51112 in Rechnung zu stellen:\n" + // + " \n" + // + " \n" + // + " \n"; xml = xml + " \n" //$NON-NLS-1$ + ""; //$NON-NLS-1$ @@ -436,9 +558,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { zugferdData = zugferdRaw; } } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } //$NON-NLS-1$ + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); + } // $NON-NLS-1$ } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java index e5504667..0330c4e4 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporter.java @@ -33,6 +33,7 @@ import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.pdmodel.*; import org.apache.pdfbox.pdmodel.common.PDMetadata; import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification; @@ -55,7 +56,7 @@ public class ZUGFeRDExporter implements Closeable { public static final int DefaultZUGFeRDVersion = 1; - private static boolean isFacturX = false; + private boolean isFacturX = false; /** * To use the ZUGFeRD exporter, implement IZUGFeRDExportableTransaction in @@ -96,7 +97,7 @@ public class ZUGFeRDExporter implements Closeable { */ protected String producer = "mustangproject"; /** - * Author/Creator attribute for PDF for PDF + * Author/Creator attribute for PDF */ protected String creator = "mustangproject"; /** @@ -133,7 +134,7 @@ public class ZUGFeRDExporter implements Closeable { additionalXMLs.put(filename, xml); } - public static String getNamespaceForVersion(int ver) { + public String getNamespaceForVersion(int ver) { if (isFacturX) { return "urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#"; } else if (ver == 1) { @@ -146,7 +147,7 @@ public class ZUGFeRDExporter implements Closeable { } } - public static String getPrefixForVersion(int ver) { + public String getPrefixForVersion(int ver) { if (isFacturX) { return "fx"; } else { @@ -154,11 +155,15 @@ public class ZUGFeRDExporter implements Closeable { } } - public static String getFilenameForVersion(int ver) { + public String getFilenameForVersion(int ver) { if (isFacturX) { return "factur-x.xml"; } else { - return "ZUGFeRD-invoice.xml"; + if (ver==1) { + return "ZUGFeRD-invoice.xml"; + } else { + return "zugferd-invoice.xml"; + } } } @@ -191,15 +196,16 @@ public class ZUGFeRDExporter implements Closeable { /** * All files are PDF/A-3, setConformance refers to the level conformance. - *

+ * * PDF/A-3 has three conformance levels, called "A", "U" and "B". - *

+ *

* PDF/A-3-B where B means only visually preservable, U -standard for Mustang- * means visually and unicode preservable and A means full compliance, i.e. * visually, unicode and structurally preservable and tagged PDF, i.e. useful * metainformation for blind people. - *

+ *

* Feel free to pass "A" as new level if you know what you are doing :-) + * @param newLevel "A", "U" or "B" * * @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead */ @@ -213,16 +219,17 @@ public class ZUGFeRDExporter implements Closeable { /** * All files are PDF/A-3, setConformance refers to the level conformance. - *

+ *

* PDF/A-3 has three conformance levels, called "A", "U" and "B". - *

+ *

* PDF/A-3-B where B means only visually preservable, U -standard for Mustang- * means visually and unicode preservable and A means full compliance, i.e. * visually, unicode and structurally preservable and tagged PDF, i.e. useful * metainformation for blind people. - *

+ *

* Feel free to pass "A" as new level if you know what you are doing :-) * + * @param newLevel "A", "U" or "B" * @deprecated Use * {@link #setConformanceLevel(org.mustangproject.ZUGFeRD.PDFAConformanceLevel)} * instead @@ -247,27 +254,45 @@ public class ZUGFeRDExporter implements Closeable { ignoreA1Errors = true; } - /** + /*** + * load from a pdf which is already A/3 + * @param filename the PDF + * @throws IOException if anything is wrong with filename * @deprecated Use the factory method {@link #createFromPDFA3(String)} instead */ @Deprecated public void loadPDFA3(String filename) throws IOException { doc = PDDocument.load(new File(filename)); } - + + /*** + * factory create a ZUGFeRD exporter for a PDF/A-3 pdf file + * @param filename of the pdf + * @return the created ZUGFeRDExporter + * @throws IOException if something is wrong with filename + */ public static ZUGFeRDExporter createFromPDFA3(String filename) throws IOException { return new ZUGFeRDExporter(PDDocument.load(new File(filename))); } /** - * @deprecated Use the factory method {@link #createFromPDFA3(InputStream)} - * instead + * load from a pdf which is already A/3 from filestream + * @param file InputStream to load pdf from + * @deprecated Use the factory method {@link #createFromPDFA3(InputStream)} instead + * @throws IOException in case anything is wrong with file + * */ @Deprecated public void loadPDFA3(InputStream file) throws IOException { doc = PDDocument.load(file); } + /*** + * factory create a ZUGFeRD exporter for a PDF/A-3 inputstream + * @param pdfSource the InputStream of the pdf + * @return the created ZUGFeRDExporter + * @throws IOException (should not happen) + */ public static ZUGFeRDExporter createFromPDFA3(InputStream pdfSource) throws IOException { return new ZUGFeRDExporter(PDDocument.load(pdfSource)); } @@ -275,7 +300,13 @@ public class ZUGFeRDExporter implements Closeable { /** * Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the * metadata level, this will not e.g. convert graphics to JPG-2000) - * + * @param filename the pdf + * @param producer the name of the xmp producer (app) + * @param creator the name of the xmp creator (user) + * @param attachZugferdHeaders whether to attach XMP ZUGFeRD headers + * @return the created PDFbox PDDocumentCatalog + * @throws IOException if anything is wrong with file + * @throws TransformerException in case of xml (XMP) parsing issues * @deprecated use the {@link ZUGFeRDExporterFromA1Factory} instead */ @Deprecated @@ -287,7 +318,18 @@ public class ZUGFeRDExporter implements Closeable { return doc.getDocumentCatalog(); } - /** + /*** + * + * Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the + * metadata level, this will not e.g. convert graphics to JPG-2000) + + * @param file the InputStream of the pdf + * @param producer the name of the xmp producer (app) + * @param creator the name of the xmp creator (user) + * @param attachZugferdHeaders whether to attach XMP ZUGFeRD headers + * @return the created PDFbox PDDocumentCatalog + * @throws IOException if anything is wrong with file + * @throws TransformerException in case of xml (XMP) parsing issues * @deprecated use the {@link ZUGFeRDExporterFromA1Factory} instead */ @Deprecated @@ -299,6 +341,7 @@ public class ZUGFeRDExporter implements Closeable { return doc.getDocumentCatalog(); } + private IExporterFactory createPDFA1Factory() { ZUGFeRDExporterFromA1Factory factory = new ZUGFeRDExporterFromA1Factory(); if (ignoreA1Errors) { @@ -321,10 +364,11 @@ public class ZUGFeRDExporter implements Closeable { * populate the XML. This parameter may be null, if so the XML data * should hav ebeen set via * setZUGFeRDXMLData(byte[] zugferdData) + * @throws IOException if anything is wrong with already loaded PDF */ public void PDFattachZugferdFile(IZUGFeRDExportableTransaction trans) throws IOException { prepareDocument(); - + ((IProfileProvider) xmlProvider).setProfile(profile); xmlProvider.generateXML(trans); String filename = getFilenameForVersion(ZFVersion); PDFAttachGenericFile(doc, filename, "Alternative", @@ -335,6 +379,11 @@ public class ZUGFeRDExporter implements Closeable { } } + /*** + * Perform the final export to a now ZUGFeRD-enriched PDF file + * @param ZUGFeRDfilename the pdf file name + * @throws IOException if anything is wrong in the target location + */ public void export(String ZUGFeRDfilename) throws IOException { if (!documentPrepared) { prepareDocument(); @@ -349,8 +398,17 @@ public class ZUGFeRDExporter implements Closeable { } } + + /*** + * Perform the final export to a now ZUGFeRD-enriched PDF file as OutputStream + * @param output the OutputStream + * @throws IOException if anything is wrong in the OutputStream + */ public void export(OutputStream output) throws IOException { - if (!fileAttached) { + if (!documentPrepared) { + prepareDocument(); + } + if ((!fileAttached) && (attachZUGFeRDHeaders)) { throw new IOException( "File must be attached (usually with PDFattachZugferdFile) before perfoming this operation"); } @@ -369,7 +427,7 @@ public class ZUGFeRDExporter implements Closeable { * @param description Human-readable description of the file content * @param subType type of the data e.g. could be "text/xml" - mime like * @param data the binary data of the file/attachment - * @throws java.io.IOException + * @throws java.io.IOException if anything is wrong with filename */ public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description, String subType, byte[] data) throws IOException { @@ -421,17 +479,27 @@ public class ZUGFeRDExporter implements Closeable { doc.getDocumentCatalog().setNames(names); // AF entry (Array) in catalog with the FileSpec - COSArray cosArray = (COSArray) doc.getDocumentCatalog().getCOSObject().getItem("AF"); - if (cosArray == null) { - cosArray = new COSArray(); - } - cosArray.add(fs); - COSDictionary dict2 = doc.getDocumentCatalog().getCOSObject(); - COSArray array = new COSArray(); - array.add(fs.getCOSObject()); // see below - dict2.setItem("AF", array); - doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray); - } + COSBase AFEntry = (COSBase)doc.getDocumentCatalog().getCOSObject().getItem("AF"); + if ((AFEntry == null)) + { + COSArray cosArray = new COSArray(); + cosArray.add(fs); + doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray); + } else if (AFEntry instanceof COSArray) + { + COSArray cosArray = (COSArray)AFEntry; + cosArray.add(fs); + doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray); + } else if ((AFEntry instanceof COSObject) && + ((COSObject)AFEntry).getObject() instanceof COSArray) + { + COSArray cosArray = (COSArray)((COSObject)AFEntry).getObject(); + cosArray.add(fs); + } else + { + throw new IOException("Unexpected object type for PDFDocument/Catalog/COSDictionary/Item(AF)"); + } + } /** * Sets the ZUGFeRD XML data to be attached as a single byte array. This is @@ -439,6 +507,7 @@ public class ZUGFeRDExporter implements Closeable { * API or component. * * @param zugferdData XML data to be set as a byte array (XML file in raw form). + * @throws IOException (should not happen) */ public void setZUGFeRDXMLData(byte[] zugferdData) throws IOException { CustomXMLProvider cus = new CustomXMLProvider(); @@ -488,19 +557,19 @@ public class ZUGFeRDExporter implements Closeable { * neccessary PDF/A schema extension description to be able to add this * information to RDF * - * @param metadata + * @param metadata the PDFbox XMPMetadata object */ protected void addXMP(XMPMetadata metadata) { if (attachZUGFeRDHeaders) { XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, profile, - ZUGFeRDExporter.getNamespaceForVersion(ZFVersion), ZUGFeRDExporter.getPrefixForVersion(ZFVersion), - ZUGFeRDExporter.getFilenameForVersion(ZFVersion)); + getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion), + getFilenameForVersion(ZFVersion)); metadata.addSchema(zf); } - XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(metadata, ZFVersion, attachZUGFeRDHeaders); + XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(this, metadata, ZFVersion, attachZUGFeRDHeaders); pdfaex.setZUGFeRDVersion(ZFVersion); metadata.addSchema(pdfaex); @@ -517,12 +586,12 @@ public class ZUGFeRDExporter implements Closeable { buffer.write(prefix.getBytes("UTF-8")); // see https://github.com/ZUGFeRD/mustangproject/issues/44 serializer.serialize(xmpMetadata, buffer, false); buffer.write(suffix.getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + } catch (UnsupportedEncodingException e) + { + throw new TransformerException(e); + } catch (IOException e) + { + throw new TransformerException(e); } return buffer.toByteArray(); } @@ -600,7 +669,7 @@ public class ZUGFeRDExporter implements Closeable { /** * the human author (use factory method instead) * - * @param creator + * @param creator the (human) name who created the PDF */ @Deprecated public void setCreator(String creator) { @@ -610,7 +679,7 @@ public class ZUGFeRDExporter implements Closeable { /** * the CreatorTool attribute for the PDF * - * @param creator + * @param creatorTool the application which created the PDF */ protected void setCreatorTool(String creatorTool) { this.creatorTool = creatorTool; @@ -619,7 +688,7 @@ public class ZUGFeRDExporter implements Closeable { /** * the authoring software (use factory method instead) * - * @param producer + * @param producer the authoring software */ @Deprecated public void setProducer(String producer) { @@ -640,4 +709,17 @@ public class ZUGFeRDExporter implements Closeable { this.attachZUGFeRDHeaders = attachZUGFeRDHeaders; } + /** + * encapsulate the deprecated setters + * @param zfVersion 1 or 2 + * @param zugferdConformanceLevel BASIC, COMFORT, EN16931, etc. + * @param creator PDF creator + * @param producer PDF producer + */ + public void configure(int zfVersion, ZUGFeRDConformanceLevel zugferdConformanceLevel, String creator, String producer) { + setZUGFeRDVersion(zfVersion); + setZUGFeRDConformanceLevel(zugferdConformanceLevel); + setCreator(creator); + setProducer(producer); + } } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java index a0a5cb20..483f174f 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDExporterFromA3Factory.java @@ -63,20 +63,9 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { public ZUGFeRDExporter load(String pdfFilename) throws IOException { ensurePDFIsValidPDFA(new FileDataSource(pdfFilename)); - ZUGFeRDExporter zugFeRDExporter; - PDDocument doc = PDDocument.load(new File(pdfFilename)); - zugFeRDExporter = new ZUGFeRDExporter(doc); - zugFeRDExporter.setZUGFeRDVersion(ZFVersion); - zugFeRDExporter.setZUGFeRDConformanceLevel(zugferdConformanceLevel); - zugFeRDExporter.setCreator(creator); - // Use creator as default for compatibility - zugFeRDExporter.setCreatorTool(creatorTool != null ? creatorTool : creator); - zugFeRDExporter.setProducer(producer); - zugFeRDExporter.setAttachZUGFeRDHeaders(attachZUGFeRDHeaders); - zugFeRDExporter.setPDFA3(ensurePDFisUpgraded); - - return zugFeRDExporter; - + try (FileInputStream pdf = new FileInputStream(pdfFilename)) { + return load(readAllBytes(pdf)); + } } @@ -88,13 +77,9 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { */ public ZUGFeRDExporter load(byte[] pdfBinary) throws IOException { ensurePDFIsValidPDFA(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary))); - ZUGFeRDExporter zugFeRDExporter; PDDocument doc = PDDocument.load(pdfBinary); - zugFeRDExporter = new ZUGFeRDExporter(doc); - zugFeRDExporter.setZUGFeRDVersion(ZFVersion); - zugFeRDExporter.setZUGFeRDConformanceLevel(zugferdConformanceLevel); - zugFeRDExporter.setCreator(creator); - zugFeRDExporter.setProducer(producer); + ZUGFeRDExporter zugFeRDExporter = new ZUGFeRDExporter(doc); + zugFeRDExporter.configure(ZFVersion, zugferdConformanceLevel, creator, producer); zugFeRDExporter.setAttachZUGFeRDHeaders(attachZUGFeRDHeaders); zugFeRDExporter.setPDFA3(ensurePDFisUpgraded); @@ -173,14 +158,14 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory { /** * All files are PDF/A-3, setConformance refers to the level conformance. - *

+ *

* PDF/A-3 has three coformance levels, called "A", "U" and "B". - *

+ *

* PDF/A-3-B where B means only visually preservable, U -standard for Mustang- * means visually and unicode preservable and A means full compliance, i.e. * visually, unicode and structurally preservable and tagged PDF, i.e. useful * metainformation for blind people. - *

+ *

* Feel free to pass "A" as new level if you know what you are doing :-) */ public IExporterFactory setConformanceLevel(PDFAConformanceLevel newLevel) { diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java index 6b2a1acb..e748332c 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java @@ -32,6 +32,7 @@ import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode; import org.apache.pdfbox.pdmodel.common.PDNameTreeNode; import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification; import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile; +import org.mustangproject.toecount.Toecount; import org.w3c.dom.Document; import org.xml.sax.SAXException; @@ -45,31 +46,41 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; public class ZUGFeRDImporter { /** - * @var if metadata has been found + * if metadata has been found */ private boolean containsMeta = false; /** - * @var the reference (i.e. invoice number) of the sender + * map filenames of additional XML files to their contents */ private HashMap additionalXMLs = new HashMap<>(); /** * Raw XML form of the extracted data - may be directly obtained. */ private byte[] rawXML = null; + /** + * XMP metadata + */ private String xmpString = null; // XMP metadata + /** + * parsed Document + */ + private Document document; public ZUGFeRDImporter(String pdfFilename) { - try { - BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pdfFilename)); + try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) { extractLowLevel(bis); - bis.close(); } catch (IOException e) { - e.printStackTrace(); + Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); throw new ZUGFeRDExportException(e); } } @@ -78,7 +89,7 @@ public class ZUGFeRDImporter { try { extractLowLevel(pdfStream); } catch (IOException e) { - e.printStackTrace(); + Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); throw new ZUGFeRDExportException(e); } } @@ -122,15 +133,16 @@ public class ZUGFeRDImporter { private void extractFiles(Map names) throws IOException { - for (String filename : names.keySet()) { + for (String alias : names.keySet()) { + + PDComplexFileSpecification fileSpec = names.get(alias); + String filename=fileSpec.getFilename(); /** - * currently (in the release candidate of version 1) only one attached file with - * the name ZUGFeRD-invoice.xml is allowed + * filenames for invoice data (ZUGFeRD v1 and v2, Factur-X) */ - if ((filename.equals("ZUGFeRD-invoice.xml") || filename.equals("factur-x.xml"))) { //$NON-NLS-1$ + if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml"))) { //$NON-NLS-1$ containsMeta = true; - PDComplexFileSpecification fileSpec = names.get(filename); PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile(); // String embeddedFilename = filePath + filename; // File file = new File(filePath + filename); @@ -139,18 +151,14 @@ public class ZUGFeRDImporter { // ByteArrayOutputStream(); // FileOutputStream fos = new FileOutputStream(file); - rawXML = embeddedFile.toByteArray(); - setMeta(new String(rawXML)); + setRawXML(embeddedFile.toByteArray()); // fos.write(embeddedFile.getByteArray()); // fos.close(); } if (filename.startsWith("additional_data")) { - - PDComplexFileSpecification fileSpec = names.get(filename); PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile(); additionalXMLs.put(filename, embeddedFile.toByteArray()); - } } } @@ -161,7 +169,7 @@ public class ZUGFeRDImporter { try { transformer = tf.newTransformer(); } catch (TransformerConfigurationException e) { - e.printStackTrace(); + Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); } transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); StringWriter writer = new StringWriter(); @@ -170,13 +178,52 @@ public class ZUGFeRDImporter { System.err.println(output); } - private Document getDocument() throws ParserConfigurationException, IOException, SAXException, TransformerException { + private Document getDocument() { return document; } + + private void setDocument() throws ParserConfigurationException, IOException, SAXException { DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance(); xmlFact.setNamespaceAware(false); DocumentBuilder builder = xmlFact.newDocumentBuilder(); - Document doc = builder.parse(new ByteArrayInputStream(rawXML)); - //prettyPrint(doc); - return doc; + ByteArrayInputStream is = new ByteArrayInputStream(rawXML); + is.skip(guessBOMSize(is)); + document = builder.parse(is); + } + + public void setRawXML(byte[] rawXML) throws IOException { + this.rawXML = rawXML; + try { + setDocument(); + } catch (ParserConfigurationException | SAXException e) { + Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); + throw new ZUGFeRDExportException(e); + } + } + + /** + * Skips over a BOM at the beginning of the given ByteArrayInputStream, if one exists. + * @param is the ByteArrayInputStream used + * @throws IOException + * @see Autodetection of Character Encodings + */ + private int guessBOMSize(ByteArrayInputStream is) throws IOException { + byte[] pad = new byte[4]; + is.read(pad); + is.reset(); + int test2 = ((pad[0] & 0xFF) << 8) | (pad[1] & 0xFF); + int test3 = ((test2 & 0xFFFF) << 8) | (pad[2] & 0xFF); + int test4 = ((test3 & 0xFFFFFF) << 8) | (pad[3] & 0xFF); + // + if (test4 == 0x0000FEFF || test4 == 0xFFFE0000 || test4 == 0x0000FFFE || test4 == 0xFEFF0000) { + // UCS-4: BOM takes 4 bytes + return 4; + } else if (test3 == 0xEFBBFF) { + // UTF-8: BOM takes 3 bytes + return 3; + } else if (test2 == 0xFEFF || test2 == 0xFFFE) { + // UTF-16: BOM takes 2 bytes + return 2; + } + return 0; } private String extractString(String xpathStr) { @@ -189,11 +236,8 @@ public class ZUGFeRDImporter { XPathFactory xpathFact = XPathFactory.newInstance(); XPath xpath = xpathFact.newXPath(); result = xpath.evaluate(xpathStr, document); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - throw new ZUGFeRDExportException(e); - } catch (IOException | SAXException | TransformerException | XPathExpressionException e) { - e.printStackTrace(); + } catch (XPathExpressionException e) { + Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); throw new ZUGFeRDExportException(e); } return result; @@ -217,12 +261,30 @@ public class ZUGFeRDImporter { } /** - * @return the sender's bank's BLZ code + * @return the referred document */ + public String getReference() { + return extractString("//ApplicableHeaderTradeAgreement/BuyerReference"); + } + + /** + * @return the sender's bank's BLZ code + * @deprecated use BIC and IBAN instead of BLZ and KTO + */ + @Deprecated public String getBLZ() { return extractString("//PayeeSpecifiedCreditorFinancialInstitution/GermanBankleitzahlID"); } + /** + * @return the sender's account number + * @deprecated use BIC and IBAN instead of BLZ and KTO + */ + @Deprecated + public String getKTO() { + return extractString("//PayeePartyCreditorFinancialAccount/ProprietaryID"); + } + /** * @return the sender's bank's BIC code */ @@ -230,21 +292,21 @@ public class ZUGFeRDImporter { return extractString("//PayeeSpecifiedCreditorFinancialInstitution/BICID"); } + /** - * @return the sender's bankname + * @return the sender's bank name */ public String getBankName() { - return extractString("/CrossIndustryInvoice/SupplyChainTradeTransaction/ApplicableHeaderTradeSettlement/SpecifiedTradeSettlementPaymentMeans/PayeeSpecifiedCreditorFinancialInstitution/Name"); + return extractString("//PayeeSpecifiedCreditorFinancialInstitution/Name"); } + /** + * @return the sender's account IBAN code + */ public String getIBAN() { return extractString("//PayeePartyCreditorFinancialAccount/IBANID"); } - public String getKTO() { - return extractString("//PayeePartyCreditorFinancialAccount/ProprietaryID"); - } - public String getHolder() { return extractString("//SellerTradeParty/Name"); } @@ -290,8 +352,8 @@ public class ZUGFeRDImporter { /** * @param meta raw XML to be set */ - public void setMeta(String meta) { - this.rawXML = meta.getBytes(); + public void setMeta(String meta) throws IOException { + setRawXML(meta.getBytes()); } /** @@ -336,6 +398,7 @@ public class ZUGFeRDImporter { /** * Returns the raw XML data as extracted from the ZUGFeRD PDF file. + * @return the raw ZUGFeRD XML data */ public byte[] getRawXML() { return rawXML; @@ -359,7 +422,7 @@ public class ZUGFeRDImporter { static String convertStreamToString(java.io.InputStream is) { // source https://stackoverflow.com/questions/309424/how-do-i-read-convert-an-inputstream-into-a-string-in-java referring to // https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks - Scanner s = new Scanner(is).useDelimiter("\\A"); + Scanner s = new Scanner(is, "UTF-8").useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java index 3b232c17..83d67468 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java @@ -63,8 +63,22 @@ public class ZUGFeRDMigrator { */ ByteArrayOutputStream baos = new ByteArrayOutputStream(); applySchematronXsl(new FileInputStream(xmlFilename), baos); + String res = null; res = baos.toString("UTF-8"); + + //migrate the profiles + + res=res.replace("urn:ferd:CrossIndustryDocument:invoice:1p0:basic", "urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:basic"); + res=res.replace("urn:ferd:CrossIndustryDocument:invoice:1p0:comfort", "urn:cen.eu:en16931:2017"); + res=res.replace("urn:ferd:CrossIndustryDocument:invoice:1p0:extended", "urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended"); + + //somehow the XML parser seems to insert erreneous XML namespaces, depending on which one it is, saxon seems to be cleaner. + //nevertheless, remove them manually + res=res.replace("", ""); + res=res.replace("", ""); + + return res; } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java index c9343a8e..d4172098 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java @@ -19,6 +19,7 @@ package org.mustangproject.ZUGFeRD; import java.math.BigDecimal; +import java.math.RoundingMode; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.SimpleDateFormat; @@ -29,53 +30,7 @@ import java.util.HashMap; import java.util.List; import javax.xml.bind.JAXBElement; - -import org.mustangproject.ZUGFeRD.model.AmountType; -import org.mustangproject.ZUGFeRD.model.CodeType; -import org.mustangproject.ZUGFeRD.model.CountryIDType; -import org.mustangproject.ZUGFeRD.model.CreditorFinancialAccountType; -import org.mustangproject.ZUGFeRD.model.CreditorFinancialInstitutionType; -import org.mustangproject.ZUGFeRD.model.CrossIndustryDocumentType; -import org.mustangproject.ZUGFeRD.model.DateTimeType; -import org.mustangproject.ZUGFeRD.model.DateTimeTypeConstants; -import org.mustangproject.ZUGFeRD.model.DocumentCodeType; -import org.mustangproject.ZUGFeRD.model.DocumentContextParameterType; -import org.mustangproject.ZUGFeRD.model.DocumentContextParameterTypeConstants; -import org.mustangproject.ZUGFeRD.model.DocumentLineDocumentType; -import org.mustangproject.ZUGFeRD.model.ExchangedDocumentContextType; -import org.mustangproject.ZUGFeRD.model.ExchangedDocumentType; -import org.mustangproject.ZUGFeRD.model.IDType; -import org.mustangproject.ZUGFeRD.model.IndicatorType; -import org.mustangproject.ZUGFeRD.model.LogisticsServiceChargeType; -import org.mustangproject.ZUGFeRD.model.NoteType; -import org.mustangproject.ZUGFeRD.model.NoteTypeConstants; -import org.mustangproject.ZUGFeRD.model.ObjectFactory; -import org.mustangproject.ZUGFeRD.model.PaymentMeansCodeType; -import org.mustangproject.ZUGFeRD.model.PaymentMeansCodeTypeConstants; -import org.mustangproject.ZUGFeRD.model.PercentType; -import org.mustangproject.ZUGFeRD.model.QuantityType; -import org.mustangproject.ZUGFeRD.model.ReferencedDocumentType; -import org.mustangproject.ZUGFeRD.model.SupplyChainEventType; -import org.mustangproject.ZUGFeRD.model.SupplyChainTradeAgreementType; -import org.mustangproject.ZUGFeRD.model.SupplyChainTradeDeliveryType; -import org.mustangproject.ZUGFeRD.model.SupplyChainTradeLineItemType; -import org.mustangproject.ZUGFeRD.model.SupplyChainTradeSettlementType; -import org.mustangproject.ZUGFeRD.model.SupplyChainTradeTransactionType; -import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeType; -import org.mustangproject.ZUGFeRD.model.TaxRegistrationType; -import org.mustangproject.ZUGFeRD.model.TaxRegistrationTypeConstants; -import org.mustangproject.ZUGFeRD.model.TaxTypeCodeType; -import org.mustangproject.ZUGFeRD.model.TaxTypeCodeTypeConstants; -import org.mustangproject.ZUGFeRD.model.TextType; -import org.mustangproject.ZUGFeRD.model.TradeAddressType; -import org.mustangproject.ZUGFeRD.model.TradeAllowanceChargeType; -import org.mustangproject.ZUGFeRD.model.TradePartyType; -import org.mustangproject.ZUGFeRD.model.TradePaymentTermsType; -import org.mustangproject.ZUGFeRD.model.TradePriceType; -import org.mustangproject.ZUGFeRD.model.TradeProductType; -import org.mustangproject.ZUGFeRD.model.TradeSettlementMonetarySummationType; -import org.mustangproject.ZUGFeRD.model.TradeSettlementPaymentMeansType; -import org.mustangproject.ZUGFeRD.model.TradeTaxType; +import org.mustangproject.ZUGFeRD.model.*; class ZUGFeRDTransactionModelConverter { private static final SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); @@ -85,6 +40,7 @@ class ZUGFeRDTransactionModelConverter { private final Totals totals; private boolean isTest; private String currency = "EUR"; + private String profile; ZUGFeRDTransactionModelConverter(IZUGFeRDExportableTransaction trans) { @@ -114,7 +70,7 @@ class ZUGFeRDTransactionModelConverter { DocumentContextParameterType contextParameter = xmlFactory .createDocumentContextParameterType(); IDType idType = xmlFactory.createIDType(); - idType.setValue(DocumentContextParameterTypeConstants.EXTENDED); + idType.setValue(profile); contextParameter.setID(idType); context.getGuidelineSpecifiedDocumentContextParameter().add( contextParameter); @@ -150,7 +106,7 @@ class ZUGFeRDTransactionModelConverter { document.setTypeCode(documentCodeType); TextType name = xmlFactory.createTextType(); - name.setValue("RECHNUNG"); + name.setValue(trans.getDocumentName()); document.getName().add(name); if (trans.getOwnOrganisationFullPlaintextInfo() != null) { @@ -168,7 +124,7 @@ class ZUGFeRDTransactionModelConverter { if (trans.getReferenceNumber() != null && !"".equals(trans.getReferenceNumber())) { NoteType referenceInfo = xmlFactory.createNoteType(); TextType referenceInfoContent = xmlFactory.createTextType(); - referenceInfoContent.setValue("Ursprungsbeleg: " + trans.getReferenceNumber()); + referenceInfoContent.setValue(trans.getReferenceNumber()); referenceInfo.getContent().add(referenceInfoContent); document.getIncludedNote().add(referenceInfo); } @@ -200,8 +156,13 @@ class ZUGFeRDTransactionModelConverter { tradeAgreement.setBuyerTradeParty(getBuyer()); tradeAgreement.setSellerTradeParty(getSeller()); - if (getBuyerOrderReferencedDocument() != null) { - tradeAgreement.getBuyerOrderReferencedDocument().add(getBuyerOrderReferencedDocument()); + if (trans.getBuyerOrderReferencedDocumentID() != null) { + ReferencedDocumentType refdoc = xmlFactory.createReferencedDocumentType(); + IDType id = xmlFactory.createIDType(); + id.setValue(trans.getBuyerOrderReferencedDocumentID()); + refdoc.getID().add(id); + refdoc.setIssueDateTime(trans.getBuyerOrderReferencedDocumentIssueDateTime()); + tradeAgreement.getBuyerOrderReferencedDocument().add(refdoc); } return tradeAgreement; @@ -232,6 +193,12 @@ class ZUGFeRDTransactionModelConverter { buyerID.setValue(trans.getRecipient().getID()); buyerTradeParty.getID().add(buyerID); } + if (trans.getRecipient().getGlobalID() != null) { + IDType globalID = xmlFactory.createIDType(); + globalID.setValue(trans.getRecipient().getGlobalID()); + globalID.setSchemeID(trans.getRecipient().getGlobalIDScheme()); + buyerTradeParty.getGlobalID().add(globalID); + } TextType buyerName = xmlFactory.createTextType(); buyerName.setValue(trans.getRecipient().getName()); @@ -410,7 +377,7 @@ class ZUGFeRDTransactionModelConverter { currencyCode.setValue(currency); tradeSettlement.setInvoiceCurrencyCode(currencyCode); - tradeSettlement.getSpecifiedTradeSettlementPaymentMeans().add( + tradeSettlement.getSpecifiedTradeSettlementPaymentMeans().addAll( getPaymentData()); tradeSettlement.getApplicableTradeTax().addAll(getTradeTax()); tradeSettlement.getSpecifiedTradePaymentTerms().addAll( @@ -434,46 +401,50 @@ class ZUGFeRDTransactionModelConverter { } - private TradeSettlementPaymentMeansType getPaymentData() { - TradeSettlementPaymentMeansType paymentData = xmlFactory - .createTradeSettlementPaymentMeansType(); - PaymentMeansCodeType paymentDataType = xmlFactory - .createPaymentMeansCodeType(); - paymentDataType.setValue(PaymentMeansCodeTypeConstants.BANKACCOUNT); - paymentData.setTypeCode(paymentDataType); + private List getPaymentData() { + List result = new ArrayList<>(); + for (IZUGFeRDTradeSettlementPayment settlementPayment : trans.getTradeSettlementPayment()) { + TradeSettlementPaymentMeansType paymentData = xmlFactory + .createTradeSettlementPaymentMeansType(); + PaymentMeansCodeType paymentDataType = xmlFactory + .createPaymentMeansCodeType(); + paymentDataType.setValue(PaymentMeansCodeTypeConstants.BANKACCOUNT); + paymentData.setTypeCode(paymentDataType); - TextType paymentInfo = xmlFactory.createTextType(); - String paymentInfoText = trans.getOwnPaymentInfoText(); - if (paymentInfoText == null) { - paymentInfoText = ""; + TextType paymentInfo = xmlFactory.createTextType(); + String paymentInfoText = settlementPayment.getOwnPaymentInfoText(); + if (paymentInfoText == null) { + paymentInfoText = ""; + } + paymentInfo.setValue(paymentInfoText); + paymentData.getInformation().add(paymentInfo); + + CreditorFinancialAccountType bankAccount = xmlFactory + .createCreditorFinancialAccountType(); + IDType iban = xmlFactory.createIDType(); + iban.setValue(settlementPayment.getOwnIBAN()); + bankAccount.setIBANID(iban); + IDType kto = xmlFactory.createIDType(); + kto.setValue(settlementPayment.getOwnKto()); + bankAccount.setProprietaryID(kto); + paymentData.setPayeePartyCreditorFinancialAccount(bankAccount); + + CreditorFinancialInstitutionType bankData = xmlFactory + .createCreditorFinancialInstitutionType(); + IDType bicId = xmlFactory.createIDType(); + bicId.setValue(settlementPayment.getOwnBIC()); + bankData.setBICID(bicId); + TextType bankName = xmlFactory.createTextType(); + bankName.setValue(settlementPayment.getOwnBankName()); + bankData.setName(bankName); + IDType blz = xmlFactory.createIDType(); + blz.setValue(settlementPayment.getOwnBLZ()); + bankData.setGermanBankleitzahlID(blz); + + paymentData.setPayeeSpecifiedCreditorFinancialInstitution(bankData); + result.add(paymentData); } - paymentInfo.setValue(paymentInfoText); - paymentData.getInformation().add(paymentInfo); - - CreditorFinancialAccountType bankAccount = xmlFactory - .createCreditorFinancialAccountType(); - IDType iban = xmlFactory.createIDType(); - iban.setValue(trans.getOwnIBAN()); - bankAccount.setIBANID(iban); - IDType kto = xmlFactory.createIDType(); - kto.setValue(trans.getOwnKto()); - bankAccount.setProprietaryID(kto); - paymentData.setPayeePartyCreditorFinancialAccount(bankAccount); - - CreditorFinancialInstitutionType bankData = xmlFactory - .createCreditorFinancialInstitutionType(); - IDType bicId = xmlFactory.createIDType(); - bicId.setValue(trans.getOwnBIC()); - bankData.setBICID(bicId); - TextType bankName = xmlFactory.createTextType(); - bankName.setValue(trans.getOwnBankName()); - bankData.setName(bankName); - IDType blz = xmlFactory.createIDType(); - blz.setValue(trans.getOwnBLZ()); - bankData.setGermanBankleitzahlID(blz); - - paymentData.setPayeeSpecifiedCreditorFinancialInstitution(bankData); - return paymentData; + return result; } @@ -490,7 +461,7 @@ class ZUGFeRDTransactionModelConverter { TaxCategoryCodeType taxCategoryCode = xmlFactory.createTaxCategoryCodeType(); VATAmount vatAmount = VATPercentAmountMap.get(currentTaxPercent); - taxCategoryCode.setValue(vatAmount.getDocumentCode()); + taxCategoryCode.setValue(vatAmount.getCategoryCode()); tradeTax.setCategoryCode(taxCategoryCode); VATAmount amount = VATPercentAmountMap.get(currentTaxPercent); @@ -754,9 +725,14 @@ class ZUGFeRDTransactionModelConverter { grandTotalAmount.setValue(currencyFormat(totals.getTotalGross())); monetarySummation.getGrandTotalAmount().add(grandTotalAmount); + AmountType totalPrepaidAmount = xmlFactory.createAmountType(); + totalPrepaidAmount.setCurrencyID(currency); + totalPrepaidAmount.setValue(currencyFormat(trans.getTotalPrepaidAmount())); + monetarySummation.getTotalPrepaidAmount().add(totalPrepaidAmount); + AmountType duePayableAmount = xmlFactory.createAmountType(); duePayableAmount.setCurrencyID(currency); - duePayableAmount.setValue(currencyFormat(totals.getTotalGross())); + duePayableAmount.setValue(currencyFormat(totals.getTotalGross().subtract(trans.getTotalPrepaidAmount()))); monetarySummation.getDuePayableAmount().add(duePayableAmount); return monetarySummation; @@ -911,70 +887,26 @@ class ZUGFeRDTransactionModelConverter { private BigDecimal vatFormat(BigDecimal value) { - return nDigitFormat(value, 2); - } + return value.setScale(2, RoundingMode.HALF_UP); + } private BigDecimal currencyFormat(BigDecimal value) { - return nDigitFormat(value, 2); - } + return value.setScale(2, RoundingMode.HALF_UP); + } private BigDecimal priceFormat(BigDecimal value) { - return nDigitFormat(value, 4); - } + return value.setScale(4, RoundingMode.HALF_UP); + } private BigDecimal quantityFormat(BigDecimal value) { - return nDigitFormat(value, 4); - } - - - private BigDecimal nDigitFormat(BigDecimal value, int scale) { - /* - * I needed 123,45, locale independent.I tried - * NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is - * locale specific.I also tried DecimalFormat df = new DecimalFormat( - * "0,00" ); df.setDecimalSeparatorAlwaysShown(true); - * df.setGroupingUsed(false); DecimalFormatSymbols symbols = new - * DecimalFormatSymbols(); symbols.setDecimalSeparator(','); - * symbols.setGroupingSeparator(' '); - * df.setDecimalFormatSymbols(symbols); - * - * but that would not switch off grouping. Although I liked very much - * the (incomplete) "BNF diagram" in - * http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html - * in the end I decided to calculate myself and take eur+sparator+cents - * - * This function will cut off, i.e. floor() subcent values Tests: - * System.err.println(utils.currencyFormat(new BigDecimal(0), - * ".")+"\n"+utils.currencyFormat(new BigDecimal("-1.10"), - * ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.1"), - * ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.01"), - * ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3489"), - * ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3419"), - * ",")+"\n"+utils.currencyFormat(new BigDecimal("12"), ",")); - * - * results 0.00 -1,10 -1,10 -1,01 20000123,34 20000123,34 12,00 - */ - value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); // first, round - // so that - // e.g. - // 1.189999999999999946709294817992486059665679931640625 - // becomes - // 1.19 - char[] repeat = new char[scale]; - Arrays.fill(repeat, '0'); - - DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(); - otherSymbols.setDecimalSeparator('.'); - DecimalFormat dec = new DecimalFormat("0." + new String(repeat), - otherSymbols); - return new BigDecimal(dec.format(value)); - - } + return value.setScale(4, RoundingMode.HALF_UP); + } + /** * which taxes have been used with which amounts in this transaction, empty for no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable to 19% VAT * (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT) 190 Eur @@ -992,7 +924,7 @@ class ZUGFeRDTransactionModelConverter { for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { BigDecimal percent = currentItem.getProduct().getVATPercent(); LineCalc lc = new LineCalc(currentItem); - VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), trans.getDocumentCode()); + VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), lc.getCategoryCode()); VATAmount current = hm.get(percent); if (current == null) { hm.put(percent, itemVATAmount); @@ -1027,8 +959,7 @@ class ZUGFeRDTransactionModelConverter { VATAmount itemVATAmount = new VATAmount( logisticsServiceCharge.getTotalAmount(), logisticsServiceCharge.getTotalAmount() - .multiply(percent).divide(new BigDecimal(100)), - trans.getDocumentCode()); + .multiply(percent).divide(new BigDecimal(100)), logisticsServiceCharge.getCategoryCode()); VATAmount current = hm.get(percent); if (current == null) { hm.put(percent, itemVATAmount); @@ -1043,8 +974,7 @@ class ZUGFeRDTransactionModelConverter { BigDecimal percent = charge.getTaxPercent(); VATAmount itemVATAmount = new VATAmount( charge.getTotalAmount(), charge.getTotalAmount() - .multiply(percent).divide(new BigDecimal(100)), - trans.getDocumentCode()); + .multiply(percent).divide(new BigDecimal(100)), charge.getCategoryCode()); VATAmount current = hm.get(percent); if (current == null) { hm.put(percent, itemVATAmount); @@ -1063,12 +993,18 @@ class ZUGFeRDTransactionModelConverter { return this; } + public ZUGFeRDTransactionModelConverter withProfile(String profile) { + this.profile = profile; + return this; + } + private class LineCalc { private BigDecimal totalGross; private BigDecimal itemTotalNetAmount; private BigDecimal itemTotalVATAmount; private BigDecimal itemNetAmount; + private String categoryCode; public LineCalc(IZUGFeRDExportableItem currentItem) { @@ -1111,6 +1047,7 @@ class ZUGFeRDTransactionModelConverter { .add(totalCharge) .divide(currentItem.getQuantity(), 4, BigDecimal.ROUND_HALF_UP); + categoryCode = currentItem.getCategoryCode(); } @@ -1128,6 +1065,8 @@ class ZUGFeRDTransactionModelConverter { return itemNetAmount; } + public String getCategoryCode() { return categoryCode; } + } private class Totals { diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java new file mode 100644 index 00000000..eb75f9dd --- /dev/null +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -0,0 +1,165 @@ +/** ********************************************************************** + * + * Copyright 2018 Jochen Staerk + * + * Use is subject to license terms. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ +package org.mustangproject.ZUGFeRD; + +import javax.xml.transform.*; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class ZUGFeRDVisualizer { + + static final ClassLoader CLASS_LOADER = ZUGFeRDVisualizer.class.getClassLoader(); + private static final String RESOURCE_PATH = ""; //$NON-NLS-1$ + private static final Logger LOG = Logger.getLogger(ZUGFeRDVisualizer.class.getName()); + // private static File createTempFileResult(final Transformer transformer, final + // StreamSource toTransform, + // final String suffix) throws TransformerException, IOException { + // File result = File.createTempFile("ZUV_", suffix); //$NON-NLS-1$ + // result.deleteOnExit(); + // + // try (FileOutputStream fos = new FileOutputStream(result)) { + // transformer.transform(toTransform, new StreamResult(fos)); + // } + // return result; + // } + private TransformerFactory mFactory = null; + private Templates mXsltXRTemplate = null; + private Templates mXsltHTMLTemplate = null; + private Templates mXsltZF1HTMLTemplate = null; + + public ZUGFeRDVisualizer() { + mFactory = new net.sf.saxon.TransformerFactoryImpl(); + // fact = TransformerFactory.newInstance(); + mFactory.setURIResolver(new ClasspathResourceURIResolver()); + try { + mXsltXRTemplate = mFactory.newTemplates( + new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl"))); + mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource( + CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html.xsl"))); + mXsltZF1HTMLTemplate = mFactory.newTemplates(new StreamSource( + CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt"))); + } catch (TransformerConfigurationException ex) { + LOG.log(Level.SEVERE, null, ex); + } + } + + public String visualize(String xmlFilename) + throws FileNotFoundException, TransformerException, UnsupportedEncodingException { + /** + * * + * http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf + * http://www.ferd-net.de/upload/Dokumente/FACTUR-X_ZUGFeRD_2p0_Teil1_Profil_EN16931_1p03.pdf + * http://countwordsfree.com/xmlviewer + */ + FileInputStream fis=new FileInputStream(xmlFilename); + String fileContent=""; + try { + fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename))); + } catch (IOException e2) { + LOG.log(Level.SEVERE, null, e2); + } + + ByteArrayOutputStream iaos = new ByteArrayOutputStream(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + String zf1Signature = "rsm:CrossIndustryDocument"; + if (fileContent.contains(zf1Signature)) { + applyZF1SchematronXsl(fis, baos); + + } else { + //zf2 or fx + applySchematronXsl(fis, iaos); + // take the copy of the stream and re-write it to an InputStream + PipedInputStream in = new PipedInputStream(); + PipedOutputStream out; + try { + out = new PipedOutputStream(in); + new Thread(new Runnable() { + public void run() { + try { + // write the original OutputStream to the PipedOutputStream + // note that in order for the below method to work, you need + // to ensure that the data has finished writing to the + // ByteArrayOutputStream + iaos.writeTo(out); + } catch (IOException e) { + LOG.log(Level.SEVERE, null, e); + } finally { + // close the PipedOutputStream here because we're done writing data + // once this thread has completed its run + if (out != null) { + // close the PipedOutputStream cleanly + try { + out.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + LOG.log(Level.SEVERE, null, e); + } + } + } + } + }).start(); + applySchematronXsl2(in, baos); + } catch (IOException e1) { + LOG.log(Level.SEVERE, null, e1); + } + } + + return baos.toString("UTF-8"); + } + + public void applySchematronXsl(final InputStream xmlFile, final OutputStream HTMLOutstream) + throws TransformerException { + Transformer transformer = mXsltXRTemplate.newTransformer(); + + transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream)); + } + + public void applyZF1SchematronXsl(final InputStream xmlFile, final OutputStream HTMLOutstream) + throws TransformerException { + Transformer transformer = mXsltZF1HTMLTemplate.newTransformer(); + + transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream)); + } + + public void applySchematronXsl2(final InputStream xmlFile, final OutputStream HTMLOutstream) + throws TransformerException { + Transformer transformer = mXsltHTMLTemplate.newTransformer(); + + transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream)); + } + + private static class ClasspathResourceURIResolver implements URIResolver { + ClasspathResourceURIResolver() { + // Do nothing, just prevents synthetic access warning. + } + + @Override + public Source resolve(String href, String base) throws TransformerException { + return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + href)); + } + } +} diff --git a/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentContextParameterTypeConstants.java b/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentContextParameterTypeConstants.java index 57033f6d..d90eabd1 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentContextParameterTypeConstants.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/model/DocumentContextParameterTypeConstants.java @@ -19,7 +19,7 @@ package org.mustangproject.ZUGFeRD.model; public class DocumentContextParameterTypeConstants { + public static final String BASIC = "urn:ferd:CrossIndustryDocument:invoice:1p0:basic"; public static final String COMFORT = "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort"; public static final String EXTENDED = "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"; - // this does not look complete :-/ } diff --git a/src/main/java/org/mustangproject/toecount/Toecount.java b/src/main/java/org/mustangproject/toecount/Toecount.java index 2cf1c3b3..688dcda2 100755 --- a/src/main/java/org/mustangproject/toecount/Toecount.java +++ b/src/main/java/org/mustangproject/toecount/Toecount.java @@ -30,8 +30,14 @@ import org.mustangproject.ZUGFeRD.*; import javax.xml.transform.TransformerException; import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -69,8 +75,9 @@ public class Toecount { + " [--source ]: set input PDF file\n" + " [--source-xml ]: set input XML file\n" + " [--out ]: set output PDF file\n" - + " [--zugferd-version <1|2>]: set ZUGFeRD version\n" - + " [--zugferd-profile <...>]: set ZUGFeRD profile\n" + + " [--format ]: set ZUGFeRD or FacturX\n" + + " [--version <1|2>]: set ZUGFeRD version\n" + + " [--profile <...>]: set ZUGFeRD profile\n" + " For ZUGFeRD v1: ASIC, OMFORT or XTENDED\n" + " For ZUGFeRD v2: INIMUM, BASIC L, ASIC, IUS, N16931, ETENDED "; } @@ -102,8 +109,8 @@ public class Toecount { + "\t\t[--source ]: set input PDF file\r\n" + "\t\t[--source-xml ]: set input XML file\r\n" + "\t\t[--out ]: set output PDF file\r\n" - + "\t\t[--zugferd-version <1|2>]: set ZUGFeRD version\r\n" - + "\t\t[--zugferd-profile <...>]: set ZUGFeRD profile\r\n" + + "\t\t[--format ]: enable factur-x or ZUGFeRD\r\n" + + "\t\t[--version <1|2>]: set ZUGFeRD version\r\n" + "\t\t[--profile <...>]: set ZUGFeRD profile\r\n" + "\t\t\tFor ZUGFeRD v1: ASIC, OMFORT or XTENDED\r\n" + "\t\t\tFor ZUGFeRD v2: INIMUM, BASIC L, ASIC, IUS, N16931, ETENDED\r\n"); } @@ -112,11 +119,15 @@ public class Toecount { * Asks the user (repeatedly, if neccessary) on the command line for a String * (offering a defaultValue) conforming to a Regex pattern * - * @param prompt the question to be asked to the user - * @param defaultValue the default return value if user hits enter - * @param pattern a regex of acceptable values + * @param prompt + * the question to be asked to the user + * @param defaultValue + * the default return value if user hits enter + * @param pattern + * a regex of acceptable values * @return the user answer conforming to pattern - * @throws Exception if pattern not compielable or IOexception on input + * @throws Exception + * if pattern not compielable or IOexception on input */ protected static String getStringFromUser(String prompt, String defaultValue, String pattern) throws Exception { String input = ""; @@ -137,8 +148,8 @@ public class Toecount { try { input = buffer.readLine(); } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); + } if (input.isEmpty()) { @@ -155,15 +166,15 @@ public class Toecount { /** * Prompts the user for a input or output filename * - * @param the text the user is asked - * @param a default Filename - * @param expectedExtension will warn if filename does not match expected file extension - * @param ensureFileExists will warn if file does NOT exist (for input files) + * @param prompt the text the user is asked + * @param defaultFilename a default Filename + * @param expectedExtension will warn if filename does not match expected file extension + * @param ensureFileExists will warn if file does NOT exist (for input files) * @param ensureFileNotExists will warn if file DOES exist (for output files) * @return String */ protected static String getFilenameFromUser(String prompt, String defaultFilename, String expectedExtension, - boolean ensureFileExists, boolean ensureFileNotExists) { + boolean ensureFileExists, boolean ensureFileNotExists) { boolean fileExistenceOK = false; String selectedName = ""; do { @@ -174,8 +185,8 @@ public class Toecount { try { selectedName = buffer.readLine(); } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); + } if (selectedName.isEmpty()) { @@ -191,8 +202,7 @@ public class Toecount { try { selectedAnswer = buffer.readLine(); } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); } if (!selectedAnswer.equals("Y") && !selectedAnswer.equals("y")) { System.err.println("Aborted by user"); @@ -234,6 +244,8 @@ public class Toecount { // Option: Help Option helpOption = parser.addBooleanOption('h', "help"); + // Option: Action + Option actionOption = parser.addStringOption('a', "action"); // Generic options available for multiple command // --source: input file @@ -264,12 +276,13 @@ public class Toecount { // (--source: input PDF file) // (--source-xml: input XML file) // (--out: output PDF file) - // (--zugferd-version: ZUGFeRD version) - // (--zugferd-profile: ZUGFeRD profile) + // (--version: ZUGFeRD version) + // (--profile: ZUGFeRD profile) Option combineOption = parser.addBooleanOption('c', "combine"); Option sourceXmlOption = parser.addStringOption("source-xml"); - Option zugferdVersionOption = parser.addStringOption("zugferd-version"); - Option zugferdProfileOption = parser.addStringOption("zugferd-profile"); + Option formatOption = parser.addStringOption('f', "format"); + Option zugferdVersionOption = parser.addStringOption("version"); + Option zugferdProfileOption = parser.addStringOption("profile"); // Command: Show metrics in dir // --directory @@ -290,17 +303,19 @@ public class Toecount { } // Retrieve all options + String action = parser.getOptionValue(actionOption); String directoryName = parser.getOptionValue(dirnameOption); Boolean filesFromStdIn = parser.getOptionValue(filesFromStdInOption, Boolean.FALSE); - Boolean combineRequested = parser.getOptionValue(combineOption, Boolean.FALSE); - Boolean extractRequested = parser.getOptionValue(extractOption, Boolean.FALSE); - Boolean helpRequested = parser.getOptionValue(helpOption, Boolean.FALSE); - Boolean upgradeRequested = parser.getOptionValue(upgradeOption, Boolean.FALSE); + Boolean combineRequested = parser.getOptionValue(combineOption, Boolean.FALSE) || ((action!=null)&&(action.equals("combine"))); + Boolean extractRequested = parser.getOptionValue(extractOption, Boolean.FALSE) || ((action!=null)&&(action.equals("extract"))); + Boolean helpRequested = parser.getOptionValue(helpOption, Boolean.FALSE) || ((action!=null)&&(action.equals("help"))); + Boolean upgradeRequested = parser.getOptionValue(upgradeOption, Boolean.FALSE) || ((action!=null)&&(action.equals("upgrade"))); Boolean ignoreFileExt = parser.getOptionValue(ignoreFileExtOption, Boolean.FALSE); - Boolean a3only = parser.getOptionValue(a3onlyOption, Boolean.FALSE); + Boolean a3only = parser.getOptionValue(a3onlyOption, Boolean.FALSE) || ((action!=null)&&(action.equals("a3"))); String sourceName = parser.getOptionValue(sourceOption); String sourceXMLName = parser.getOptionValue(sourceXmlOption); String outName = parser.getOptionValue(outOption); + String format = parser.getOptionValue(formatOption); String zugferdVersion = parser.getOptionValue(zugferdVersionOption); String zugferdProfile = parser.getOptionValue(zugferdProfileOption); @@ -309,7 +324,7 @@ public class Toecount { } else if (((directoryName != null) && (directoryName.length() > 0)) || filesFromStdIn.booleanValue()) { performMetrics(directoryName, filesFromStdIn, ignoreFileExt); } else if (combineRequested) { - performCombine(sourceName, sourceXMLName, outName, zugferdVersion, zugferdProfile); + performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile); } else if (extractRequested) { performExtract(sourceName, outName); } else if (a3only) { @@ -322,7 +337,7 @@ public class Toecount { System.exit(2); } } catch (Exception e) { - e.printStackTrace(); + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); System.exit(-1); } @@ -338,7 +353,7 @@ public class Toecount { System.out.println("ZUGFeRD 1.0 XML source set to " + xmlName); } if (outName == null) { - outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "factur-x.xml", "xml", false, true); + outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "zugferd-invoice.xml", "xml", false, true); } else { System.out.println("ZUGFeRD 1.0 XML source set to " + outName); } @@ -417,15 +432,15 @@ public class Toecount { } } - private static void performCombine(String pdfName, String xmlName, String outName, String zfVersion, - String zfProfile) throws Exception { + private static void performCombine(String pdfName, String xmlName, String outName, String format, String zfVersion, + String zfProfile) throws Exception { /* * ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory() * .setProducer("toecount") .setCreator(System.getProperty("user.name")) * .loadFromPDFA1("invoice.pdf"); */ try { - int zfIntVersion = 1; + int zfIntVersion = ZUGFeRDExporter.DefaultZUGFeRDVersion; ZUGFeRDConformanceLevel zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED; if (pdfName == null) { @@ -446,35 +461,42 @@ public class Toecount { System.out.println("Ouput PDF set to " + outName); } - if (zfVersion == null) { + if (format == null) { try { - zfVersion = getStringFromUser("ZUGFeRD version (1 or 2)", "1", "1|2"); + format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD,)", "zf", "fx|zf"); } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); } } else { - System.out.println("ZUGFeRD version set to " + zfVersion); + System.out.println("Format set to " + format); } + if (zfVersion == null) { + try { + zfVersion = getStringFromUser("Version (1 or 2)", "1", "1|2"); + } catch (Exception e) { + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); + } + } else { + System.out.println("Version set to " + zfVersion); + } zfIntVersion = Integer.valueOf(zfVersion); if (zfProfile == null) { try { - if (zfIntVersion == 1) { - zfProfile = getStringFromUser("ZUGFeRD profile b)asic, c)omfort or e)xtended", "e", - "B|b|C|c|E|e"); + if (format.equals("zf") && (zfIntVersion == 1)) { + zfProfile = getStringFromUser("Profile b)asic, c)omfort or e)xtended", "e", "B|b|C|c|E|e"); } else { zfProfile = getStringFromUser( - "ZUGFeRD profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, E[X]TENDED", - "E", "M|m|W|w|B|b|C|c|E|e|X|x|"); + "Profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, E[X]TENDED", "E", + "M|m|W|w|B|b|C|c|E|e|X|x|"); } } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); + } } else { - System.out.println("ZUGFeRD profile set to " + zfProfile); + System.out.println("Profile set to " + zfProfile); } zfProfile = zfProfile.toLowerCase(); @@ -483,7 +505,11 @@ public class Toecount { ensureFileExists(xmlName); ensureFileNotExists(outName); - if (zfIntVersion == 1) { + if ((format.equals("fx")) && (zfIntVersion > 1)) { + throw new Exception("Factur-X is only available in version 1 (roughly corresponding to ZF2)"); + } + + if ((format.equals("zf")) && (zfIntVersion == 1)) { if (zfProfile.equals("b")) { zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASIC; } else if (zfProfile.equals("c")) { @@ -493,7 +519,7 @@ public class Toecount { } else { throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile)); } - } else if (zfIntVersion == 2) { + } else if (((format.equals("zf")) && (zfIntVersion == 2)) || (format.equals("fx"))) { if (zfProfile.equals("m")) { zfConformanceLevelProfile = ZUGFeRDConformanceLevel.MINIMUM; } else if (zfProfile.equals("w")) { @@ -510,15 +536,18 @@ public class Toecount { throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile)); } } else { - throw new Exception(String.format("Unknown ZUGFeRD version '%i'", zfIntVersion)); + throw new Exception(String.format("Unknown version '%i'", zfIntVersion)); } // All params are good! continue... ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setProducer("Toecount") + .setZUGFeRDVersion(zfIntVersion) .setCreator(System.getProperty("user.name")).setZUGFeRDConformanceLevel(zfConformanceLevelProfile) .load(pdfName); - ze.setZUGFeRDVersion(zfIntVersion); + if (format.equals("fx")) { + ze.setFacturX(); + } ze.setZUGFeRDXMLData(Files.readAllBytes(Paths.get(xmlName))); @@ -527,9 +556,8 @@ public class Toecount { System.out.println("Written to " + outName); } catch (IOException e) { - e.printStackTrace(); - // } catch (JAXBException e) { - // e.printStackTrace(); + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); + } } diff --git a/src/main/resources/COMFORTtoEN16931.xsl b/src/main/resources/COMFORTtoEN16931.xsl index d6eb2e03..c4f974a9 100644 --- a/src/main/resources/COMFORTtoEN16931.xsl +++ b/src/main/resources/COMFORTtoEN16931.xsl @@ -63,7 +63,12 @@ Migrated by Mustangproject XSLT - + + + + + + diff --git a/src/main/resources/stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt b/src/main/resources/stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt new file mode 100644 index 00000000..bf0b71e4 --- /dev/null +++ b/src/main/resources/stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt @@ -0,0 +1,3008 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + <meta http-equiv="X-UA-Compatible" content="IE=9"/> + <xsl:comment>[if IE]><STYLE type="text/css">.altova-rotate-left-textbox{filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3)} .altova-rotate-right-textbox{filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1)} </STYLE><![endif]</xsl:comment> + <xsl:comment>[if !IE]><!</xsl:comment> + <style type="text/css">.altova-rotate-left-textbox{-webkit-transform: rotate(-90deg) translate(-100%, 0%); -webkit-transform-origin: 0% 0%;-moz-transform: rotate(-90deg) translate(-100%, 0%); -moz-transform-origin: 0% 0%;-ms-transform: rotate(-90deg) translate(-100%, 0%); -ms-transform-origin: 0% 0%;}.altova-rotate-right-textbox{-webkit-transform: rotate(90deg) translate(0%, -100%); -webkit-transform-origin: 0% 0%;-moz-transform: rotate(90deg) translate(0%, -100%); -moz-transform-origin: 0% 0%;-ms-transform: rotate(90deg) translate(0%, -100%); -ms-transform-origin: 0% 0%;}</style> + <xsl:comment><![endif]</xsl:comment> + <style type="text/css">@page { margin-left:0.60in; margin-right:0.60in; margin-top:0.79in; margin-bottom:0.79in } @media print { br.altova-page-break { page-break-before: always; } }</style> + </head> + <body style="font-family:Courier; font-size:small; "> + <xsl:for-each select="$XML"> + <xsl:for-each select="rsm:CrossIndustryDocument"> + <span> + <xsl:text>Stylesheet Lesbarmachung der XML-Daten von ZUGFeRD-Rechnungen</xsl:text> + </span> + <br/> + <span> + <xsl:text>ZUGFeRD-Version   : 1.0 vom 25.06.2014 </xsl:text> + </span> + <br/> + <span> + <xsl:text>Stylesheet-Version: 1.0 vom 25.06.2014</xsl:text> + </span> + <br/> + <span> + <xsl:text>Codelisten-Version: 1.0 vom 25.06.2014</xsl:text> + </span> + <br/> + <span> + <xsl:text>(c) AWV e.V. 2014</xsl:text> + </span> + <xsl:variable name="altova:table"> + <table style="border-collapse:collapse; " border="1" width="100%"> + <xsl:variable name="altova:CurrContextGrid_0" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <tr> + <td> + <br/> + <h2> + <xsl:for-each select="rsm:HeaderExchangedDocument"> + <xsl:for-each select="ram:Name"> + <span style="font-weight:bold; "> + <xsl:apply-templates/> + </span> + </xsl:for-each> + <span style="empty-cells:hide; font-weight:bold; "> + <xsl:text>(</xsl:text> + </span> + <xsl:for-each select="ram:TypeCode"> + <xsl:apply-templates/> + </xsl:for-each> + <span style="empty-cells:hide; font-weight:bold; "> + <xsl:text>) Nr. </xsl:text> + </span> + <xsl:for-each select="ram:ID"> + <span style="font-weight:bold; "> + <xsl:apply-templates/> + </span> + </xsl:for-each> + <span style="empty-cells:hide; font-weight:bold; "> + <xsl:text> vom </xsl:text> + </span> + <xsl:for-each select="ram:IssueDateTime"> + <xsl:for-each select="udt:DateTimeString"> + <xsl:call-template name="ram:Datum"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </h2> + <xsl:for-each select="rsm:SpecifiedExchangedDocumentContext"> + <br/> + <xsl:for-each select="ram:TestIndicator"> + <xsl:for-each select="udt:Indicator"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Testkennzeichen      : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:BusinessProcessSpecifiedDocumentContextParameter"> + <xsl:for-each select="ram:ID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Geschäftsprozess     : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedExchangedDocumentContext"> + <xsl:for-each select="ram:GuidelineSpecifiedDocumentContextParameter"> + <xsl:for-each select="ram:ID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Anwendungsempfehlung : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:HeaderExchangedDocument"> + <xsl:for-each select="ram:CopyIndicator"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Kopie                : </xsl:text> + </span> + <xsl:for-each select="udt:Indicator"> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:HeaderExchangedDocument"> + <xsl:for-each select="ram:LanguageID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Sprache              : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"> + <xsl:for-each select="ram:InvoiceCurrencyCode"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Währung              : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <br/> + </td> + </tr> + <tr> + <td> + <xsl:for-each select="rsm:HeaderExchangedDocument"> + <xsl:for-each select="ram:EffectiveSpecifiedPeriod"> + <xsl:for-each select="ram:CompleteDateTime"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Vertragliches Fälligkeitsdatum: </xsl:text> + </span> + <xsl:for-each select="udt:DateTimeString"> + <xsl:call-template name="ram:Datum"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeDelivery"> + <xsl:for-each select="ram:ActualDeliverySupplyChainEvent"> + <xsl:for-each select="ram:OccurrenceDateTime"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Liefer- und Leistungsdatum    : </xsl:text> + </span> + <xsl:for-each select="udt:DateTimeString"> + <xsl:call-template name="ram:Datum"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"> + <xsl:for-each select="ram:BillingSpecifiedPeriod"> + <xsl:for-each select="ram:StartDateTime"> + <br/> + <span> + <xsl:text>Abrechnungszeitraum           : </xsl:text> + </span> + <xsl:for-each select="udt:DateTimeString"> + <xsl:call-template name="ram:Datum"/> + </xsl:for-each> + </xsl:for-each> + <span> + <xsl:text> bis </xsl:text> + </span> + <xsl:for-each select="ram:EndDateTime"> + <xsl:for-each select="udt:DateTimeString"> + <xsl:call-template name="ram:Datum"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <br/> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeAgreement"> + <xsl:for-each select="ram:BuyerReference"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Referenz des Käufers          : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"> + <xsl:for-each select="ram:PaymentReference"> + <br/> + <span style="empty-cells:hide; font-weight:bold; "> + <xsl:text>Zahlungsreferenz              : </xsl:text> + </span> + <span style="font-weight:bold; "> + <xsl:apply-templates/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"> + <xsl:for-each select="ram:ReceivableSpecifiedTradeAccountingAccount"> + <xsl:for-each select="ram:ID"> + <br/> + <span> + <xsl:text>Buchungsreferenz              : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeAgreement"> + <xsl:for-each select="ram:ApplicableTradeDeliveryTerms"> + <xsl:for-each select="ram:DeliveryTypeCode"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Lieferbedingung (codiert)     : </xsl:text> + </span> + <xsl:call-template name="DeliveryTypeCode"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeDelivery"> + <xsl:for-each select="ram:RelatedSupplyChainConsignment"> + <xsl:for-each select="ram:SpecifiedLogisticsTransportMovement"> + <xsl:for-each select="ram:ModeCode"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Versandart (codiert)          : </xsl:text> + </span> + <xsl:call-template name="ram:VersandMode"/> + </xsl:for-each> + <xsl:for-each select="ram:ID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Versand-ID                    : </xsl:text> + </span> + <xsl:apply-templates/> + <xsl:for-each select="@schemeID"> + <span style="empty-cells:hide; "> + <xsl:text>, Art: </xsl:text> + </span> + <xsl:call-template name="ram:Versand_Identifer"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <br/> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeAgreement"> + <xsl:for-each select="ram:BuyerOrderReferencedDocument"> + <xsl:for-each select="ram:ID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Bestellung                    : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <span style="empty-cells:hide; "> + <xsl:text> vom </xsl:text> + </span> + <xsl:for-each select="ram:IssueDateTime"> + <span> + <xsl:variable name="altova:seqContentStrings_1"> + <xsl:value-of select="format-number(number(substring(string(string(.)), 9, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(.)), 6, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(string(.))), 1, 4)), '0000', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_1" select="string($altova:seqContentStrings_1)"/> + <xsl:value-of select="$altova:sContent_1"/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeDelivery"> + <xsl:for-each select="ram:DespatchAdviceReferencedDocument"> + <xsl:for-each select="ram:ID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Lieferavis                    : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <span style="empty-cells:hide; "> + <xsl:text> vom </xsl:text> + </span> + <xsl:for-each select="ram:IssueDateTime"> + <span> + <xsl:variable name="altova:seqContentStrings_2"> + <xsl:value-of select="format-number(number(substring(string(string(.)), 9, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(.)), 6, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(string(.))), 1, 4)), '0000', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_2" select="string($altova:seqContentStrings_2)"/> + <xsl:value-of select="$altova:sContent_2"/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeDelivery"> + <xsl:for-each select="ram:DeliveryNoteReferencedDocument"> + <xsl:for-each select="ram:ID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Lieferschein                  : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <span style="empty-cells:hide; "> + <xsl:text> vom </xsl:text> + </span> + <xsl:for-each select="ram:IssueDateTime"> + <span> + <xsl:variable name="altova:seqContentStrings_3"> + <xsl:value-of select="format-number(number(substring(string(string(.)), 9, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(.)), 6, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(string(.))), 1, 4)), '0000', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_3" select="string($altova:seqContentStrings_3)"/> + <xsl:value-of select="$altova:sContent_3"/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeAgreement"> + <xsl:for-each select="ram:ContractReferencedDocument"> + <xsl:for-each select="ram:ID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Vertrag                       : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <span style="empty-cells:hide; "> + <xsl:text> vom </xsl:text> + </span> + <xsl:for-each select="ram:IssueDateTime"> + <span> + <xsl:variable name="altova:seqContentStrings_4"> + <xsl:value-of select="format-number(number(substring(string(string(.)), 9, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(.)), 6, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(string(.))), 1, 4)), '0000', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_4" select="string($altova:seqContentStrings_4)"/> + <xsl:value-of select="$altova:sContent_4"/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeAgreement"> + <xsl:for-each select="ram:CustomerOrderReferencedDocument"> + <xsl:for-each select="ram:ID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Kundenbestellung              : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <span style="empty-cells:hide; "> + <xsl:text> vom </xsl:text> + </span> + <xsl:for-each select="ram:IssueDateTime"> + <span> + <xsl:variable name="altova:seqContentStrings_5"> + <xsl:value-of select="format-number(number(substring(string(string(.)), 9, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(.)), 6, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(string(.))), 1, 4)), '0000', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_5" select="string($altova:seqContentStrings_5)"/> + <xsl:value-of select="$altova:sContent_5"/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeAgreement"> + <xsl:for-each select="ram:AdditionalReferencedDocument"> + <xsl:for-each select="ram:ID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Weitere Referenz              : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <span style="empty-cells:hide; "> + <xsl:text> vom </xsl:text> + </span> + <xsl:for-each select="ram:IssueDateTime"> + <span> + <xsl:variable name="altova:seqContentStrings_6"> + <xsl:value-of select="format-number(number(substring(string(string(.)), 9, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(.)), 6, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(string(.))), 1, 4)), '0000', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_6" select="string($altova:seqContentStrings_6)"/> + <xsl:value-of select="$altova:sContent_6"/> + </span> + </xsl:for-each> + <xsl:for-each select="ram:TypeCode"> + <span style="empty-cells:hide; "> + <xsl:text>, Art der Referenz: </xsl:text> + </span> + <xsl:call-template name="ram:Referenz"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <br/> + <span style="empty-cells:hide; "> + <xsl:text> </xsl:text> + </span> + </td> + </tr> + <tr> + <td> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeAgreement"> + <xsl:for-each select="ram:SellerTradeParty"> + <br/> + <span style="empty-cells:hide; font-weight:bold; text-decoration:underline; "> + <xsl:text>Verkäufer:</xsl:text> + </span> + <br/> + <xsl:call-template name="ram:Party"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeAgreement"> + <xsl:for-each select="ram:BuyerTradeParty"> + <br/> + <span style="empty-cells:hide; font-weight:bold; text-decoration:underline; "> + <xsl:text>Käufer:</xsl:text> + </span> + <br/> + <xsl:call-template name="ram:Party"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeAgreement"> + <xsl:for-each select="ram:ProductEndUserTradeParty"> + <br/> + <span style="empty-cells:hide; font-weight:bold; text-decoration:underline; "> + <xsl:text>Endverbraucher:</xsl:text> + </span> + <br/> + <xsl:call-template name="ram:Party"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeDelivery"> + <xsl:for-each select="ram:ShipToTradeParty"> + <br/> + <span style="empty-cells:hide; font-weight:bold; text-decoration:underline; "> + <xsl:text>Abweichender Warenempfänger:</xsl:text> + </span> + <br/> + <xsl:call-template name="ram:Party"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeDelivery"> + <xsl:for-each select="ram:UltimateShipToTradeParty"> + <br/> + <span style="empty-cells:hide; font-weight:bold; text-decoration:underline; "> + <xsl:text>Abweichender Endempfänger:</xsl:text> + </span> + <br/> + <xsl:call-template name="ram:Party"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeDelivery"> + <xsl:for-each select="ram:ShipFromTradeParty"> + <br/> + <span style="empty-cells:hide; font-weight:bold; text-decoration:underline; "> + <xsl:text>Abweichender Versender:</xsl:text> + </span> + <br/> + <xsl:call-template name="ram:Party"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"> + <xsl:for-each select="ram:InvoiceeTradeParty"> + <br/> + <span style="empty-cells:hide; font-weight:bold; text-decoration:underline; "> + <xsl:text>Abweichender Rechnungsempfänger:</xsl:text> + </span> + <br/> + <xsl:call-template name="ram:Party"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"> + <xsl:for-each select="ram:PayeeTradeParty"> + <br/> + <span style="empty-cells:hide; font-weight:bold; text-decoration:underline; "> + <xsl:text>Abweichender Zahlungsempfänger:</xsl:text> + </span> + <br/> + <xsl:call-template name="ram:Party"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </td> + </tr> + <tr> + <td> + <xsl:for-each select="rsm:HeaderExchangedDocument"> + <br/> + <xsl:for-each select="ram:IncludedNote"> + <xsl:for-each select="ram:SubjectCode"> + <span style="color:gray; empty-cells:hide; "> + <xsl:text>Qualifizierung der Textart: </xsl:text> + </span> + <span style="font-weight:bold; "> + <xsl:apply-templates/> + </span> + </xsl:for-each> + <xsl:for-each select="ram:ContentCode"> + <span style="color:gray; empty-cells:hide; "> + <xsl:text>, Qualifizierung des Textes: </xsl:text> + </span> + <span style="font-weight:bold; "> + <xsl:apply-templates/> + </span> + </xsl:for-each> + <xsl:for-each select="ram:Content"> + <br/> + <span style="font-weight:bold; white-space:pre-wrap; "> + <xsl:apply-templates/> + </span> + <br/> + <br/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </td> + </tr> + <tr> + <td style="border-bottom-style:none; "> + <xsl:variable name="altova:table"> + <table style="border:0px; border-collapse:collapse; border-spacing:0px; padding:0px; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_7" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <tr style="text-align:center; vertical-align:middle; "> + <td style="border-bottom-style:solid; border-collapse:collapse; border-left-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:center; width:30px; "> + <span style="font-weight:bold; "> + <xsl:text>Pos</xsl:text> + </span> + </td> + <td style="border-bottom-style:solid; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:left; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>Art-Nr-Kunde</xsl:text> + </span> + <br/> + <span style="font-weight:bold; "> + <xsl:text>Art-Nr-Lief.</xsl:text> + </span> + <br/> + <span style="font-weight:bold; "> + <xsl:text>Art-Nr</xsl:text> + </span> + <br/> + <span style="font-weight:bold; "> + <xsl:text>(Art)</xsl:text> + </span> + </td> + <td style="border-bottom-style:solid; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; "> + <span style="font-weight:bold; "> + <xsl:text>Beschreibung</xsl:text> + </span> + </td> + <td style="border-bottom-style:solid; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>E-Preis</xsl:text> + </span> + </td> + <td style="border-bottom-style:solid; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; width:120px; "> + <span style="font-weight:bold; "> + <xsl:text>Menge</xsl:text> + </span> + </td> + <td style="border-bottom-style:solid; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>Steuer</xsl:text> + </span> + </td> + <td style="border-bottom-style:solid; border-collapse:collapse; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>Entgelt</xsl:text> + </span> + </td> + </tr> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:IncludedSupplyChainTradeLineItem"> + <xsl:if test="fn:not( fn:empty(ram:SpecifiedTradeProduct))"> + <xsl:variable name="altova:table"> + <table style="border:0px; border-collapse:collapse; border-spacing:0px; padding:0px; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_8" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <tr style="vertical-align:top; "> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:center; width:30px; "> + <xsl:for-each select="ram:AssociatedDocumentLineDocument"> + <xsl:if test="fn:empty(ram:IncludedNote)"> + <xsl:for-each select="ram:LineID"> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:if> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; width:110px; "> + <xsl:for-each select="ram:SpecifiedTradeProduct"> + <xsl:for-each select="ram:BuyerAssignedID"> + <xsl:apply-templates/> + </xsl:for-each> + <br/> + <xsl:for-each select="ram:SellerAssignedID"> + <xsl:apply-templates/> + </xsl:for-each> + <br/> + <xsl:for-each select="ram:GlobalID"> + <xsl:apply-templates/> + <br/> + <xsl:for-each select="@schemeID"> + <xsl:call-template name="ram:Global_Identifier"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; "> + <xsl:for-each select="ram:SpecifiedTradeProduct"> + <xsl:for-each select="ram:Name"> + <span style="white-space:pre-wrap; "> + <xsl:apply-templates/> + </span> + <br/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeAgreement"> + <xsl:if test="fn:exists(ram:GrossPriceProductTradePrice)"> + <xsl:for-each select="ram:GrossPriceProductTradePrice"> + <xsl:for-each select="ram:BasisQuantity"> + <span> + <xsl:text>Preisbasismenge: </xsl:text> + </span> + <xsl:call-template name="ram:Menge"/> + </xsl:for-each> + </xsl:for-each> + </xsl:if> + <xsl:if test="fn:not(fn:exists(ram:GrossPriceProductTradePrice))"> + <xsl:for-each select="ram:NetPriceProductTradePrice"> + <xsl:for-each select="ram:BasisQuantity"> + <br/> + <span> + <xsl:text>Preisbasismenge: </xsl:text> + </span> + <xsl:call-template name="ram:Menge"/> + </xsl:for-each> + </xsl:for-each> + </xsl:if> + </xsl:for-each> + </td> + <td style="border-bottom-style:solid; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; width:110px; "> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeAgreement"> + <xsl:if test="fn:exists(ram:GrossPriceProductTradePrice)"> + <xsl:for-each select="ram:GrossPriceProductTradePrice"> + <xsl:for-each select="ram:ChargeAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_9"> + <xsl:value-of select="format-number(number(string(.)), '##0,0000', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_9" select="string($altova:seqContentStrings_9)"/> + <xsl:value-of select="$altova:sContent_9"/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:if> + <xsl:if test="not(fn:exists(ram:GrossPriceProductTradePrice))"> + <xsl:for-each select="ram:NetPriceProductTradePrice"> + <xsl:for-each select="ram:ChargeAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_10"> + <xsl:value-of select="format-number(number(string(.)), '###.##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_10" select="string($altova:seqContentStrings_10)"/> + <xsl:value-of select="$altova:sContent_10"/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:if> + </xsl:for-each> + </td> + <td style="border-bottom-style:solid; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; width:120px; "> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeDelivery"> + <xsl:for-each select="ram:BilledQuantity"> + <xsl:call-template name="ram:Menge"/> + </xsl:for-each> + <xsl:for-each select="ram:ChargeFreeQuantity"> + <br/> + <span> + <xsl:text>kostenfrei:</xsl:text> + </span> + <br/> + <xsl:call-template name="ram:Menge"/> + </xsl:for-each> + </xsl:for-each> + </td> + <td style="border-bottom-style:solid; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; width:110px; "> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeSettlement"> + <xsl:for-each select="ram:ApplicableTradeTax"> + <xsl:call-template name="ram:TradeTax"/> + </xsl:for-each> + </xsl:for-each> + </td> + <td style="border-bottom-style:solid; border-collapse:collapse; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; width:110px; "> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeSettlement"> + <xsl:for-each select="ram:SpecifiedTradeSettlementMonetarySummation"> + <xsl:for-each select="ram:LineTotalAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_11"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_11" select="string($altova:seqContentStrings_11)"/> + <xsl:value-of select="$altova:sContent_11"/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </td> + </tr> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + <xsl:for-each select="ram:AssociatedDocumentLineDocument"> + <xsl:if test="fn:not( fn:empty(ram:IncludedNote))"> + <xsl:variable name="altova:table"> + <table style="border:0px; border-collapse:collapse; border-spacing:0px; border-top-style:none; padding:0px; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_12" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <tr style="empty-cells:hide; vertical-align:top; "> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:center; width:30px; "> + <xsl:for-each select="ram:LineID"> + <xsl:apply-templates/> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; width:110px; "/> + <td style="border-bottom-style:none; border-collapse:collapse; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; "> + <xsl:for-each select="ram:IncludedNote"> + <xsl:for-each select="ram:Content"> + <span style="white-space:pre-wrap; "> + <xsl:apply-templates/> + </span> + </xsl:for-each> + <xsl:for-each select="ram:SubjectCode"> + <br/> + <span style="color:gray; empty-cells:hide; "> + <xsl:text>Qualifizierung der Textart: </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:ContentCode"> + <span style="color:gray; empty-cells:hide; "> + <xsl:text>, Qualifizierung des Textes: </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <br/> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; width:110px; "/> + </tr> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeAgreement"> + <xsl:for-each select="ram:GrossPriceProductTradePrice"> + <xsl:if test="fn:not( fn:empty(ram:AppliedTradeAllowanceCharge))"> + <xsl:variable name="altova:table"> + <table style="border:0px; border-collapse:collapse; border-spacing:0px; padding:0px; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_13" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <tr style="empty-cells:hide; vertical-align:top; "> + <td style="border-bottom-style:none; border-left-style:none; border-top-style:none; width:30px; "/> + <td style="border-bottom-style:none; border-top-style:none; width:110px; "/> + <td style="border-bottom-style:none; border-right-style:none; border-top-style:none; "> + <xsl:variable name="altova:table"> + <table style="border:0px; border-style:none; padding:0px; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_14" select="."/> + <xsl:variable name="altova:ColumnData"/> + <thead> + <tr> + <th style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; font-weight:normal; text-align:left; width:70px; "> + <span style="font-style:italic; "> + <xsl:text>Art</xsl:text> + </span> + </th> + <th style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; font-weight:normal; text-align:left; "> + <span style="font-style:italic; "> + <xsl:text>Grund</xsl:text> + </span> + </th> + <th style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; font-weight:normal; text-align:right; width:70px; "> + <span style="font-style:italic; "> + <xsl:text>%</xsl:text> + </span> + </th> + <th style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; font-weight:normal; text-align:right; width:110px; "> + <span style="font-style:italic; "> + <xsl:text>Basisbetrag</xsl:text> + </span> + </th> + <th style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; font-weight:normal; text-align:right; width:120px; "> + <span style="font-style:italic; "> + <xsl:text>Basismenge</xsl:text> + </span> + </th> + <th style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; font-weight:normal; text-align:right; width:110px; "> + <span style="font-style:italic; "> + <xsl:text>Betrag</xsl:text> + </span> + </th> + <th style="border-bottom-style:none; border-left-style:none; border-right-style:none; border-top-style:none; width:112px; "/> + </tr> + </thead> + <tbody> + <xsl:for-each select="ram:AppliedTradeAllowanceCharge"> + <xsl:sort select="ram:SequenceNumeric" data-type="text" order="ascending"/> + <tr> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; vertical-align:top; width:70px; "> + <xsl:for-each select="ram:ChargeIndicator"> + <xsl:for-each select="udt:Indicator"> + <span> + <xsl:value-of select="if (. eq fn:true())then 'Zuschlag' else 'Abschlag'"/> + </span> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SequenceNumeric"> + <span> + <xsl:text> Nr. </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; vertical-align:top; "> + <xsl:for-each select="ram:Reason"> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:ReasonCode"> + <span> + <xsl:text> </xsl:text> + </span> + <xsl:call-template name="AllowanceChargeReasonCode"/> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; vertical-align:top; width:70px; "> + <xsl:for-each select="ram:CalculationPercent"> + <span> + <xsl:variable name="altova:seqContentStrings_15"> + <xsl:value-of select="format-number(number(string(.)), '###.##0,####', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_15" select="string($altova:seqContentStrings_15)"/> + <xsl:value-of select="$altova:sContent_15"/> + </span> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; vertical-align:top; width:110px; "> + <xsl:for-each select="ram:BasisAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_16"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_16" select="string($altova:seqContentStrings_16)"/> + <xsl:value-of select="$altova:sContent_16"/> + </span> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; vertical-align:top; width:120px; "> + <xsl:for-each select="ram:BasisQuantity"> + <xsl:call-template name="ram:Menge"/> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; vertical-align:top; width:110px; "> + <xsl:for-each select="ram:ActualAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_17"> + <xsl:value-of select="format-number(number(if(../ram:ChargeIndicator/udt:Indicator = fn:false()) then -1*. else .), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_17" select="string($altova:seqContentStrings_17)"/> + <xsl:value-of select="$altova:sContent_17"/> + </span> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; width:108px; "/> + </tr> + </xsl:for-each> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </td> + </tr> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + <xsl:if test="fn:exists(../../ram:SpecifiedSupplyChainTradeSettlement/ram:SpecifiedTradeSettlementMonetarySummation/ram:TotalAllowanceChargeAmount)"> + <xsl:variable name="altova:table"> + <table style="border:0px; border-collapse:collapse; border-spacing:0px; padding:0px; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_18" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <tr style="empty-cells:hide; vertical-align:top; "> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; width:30px; "/> + <td style="border-bottom-style:none; border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; width:110px; "/> + <td style="border-bottom-style:none; border-collapse:collapse; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; "> + <br/> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; width:110px; "> + <span> + <xsl:text>Summe:</xsl:text> + </span> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:double; empty-cells:hide; text-align:right; width:110px; "> + <xsl:for-each select="$XML"> + <xsl:for-each select="rsm:CrossIndustryDocument"> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:IncludedSupplyChainTradeLineItem"> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeSettlement"> + <xsl:for-each select="ram:SpecifiedTradeSettlementMonetarySummation"> + <xsl:for-each select="ram:TotalAllowanceChargeAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_19"> + <xsl:value-of select="format-number(number(-1*.), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_19" select="string($altova:seqContentStrings_19)"/> + <xsl:value-of select="$altova:sContent_19"/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; text-align:right; width:110px; "/> + </tr> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + </xsl:for-each> + </xsl:for-each> + <xsl:variable name="altova:table"> + <table style="border:0px; border-collapse:collapse; border-spacing:0px; border-top-style:none; padding:0px; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_20" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <tr style="empty-cells:hide; vertical-align:top; "> + <td style="border-collapse:collapse; border-left-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; width:30px; "/> + <td style="border-collapse:collapse; border-spacing:0px; border-top-style:none; empty-cells:hide; width:110px; "/> + <td style="border-collapse:collapse; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; "> + <xsl:for-each select="ram:SpecifiedTradeProduct"> + <xsl:for-each select="ram:Description"> + <br/> + <span style="white-space:pre-wrap; "> + <xsl:apply-templates/> + </span> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeDelivery"> + <xsl:for-each select="ram:ActualDeliverySupplyChainEvent"> + <xsl:for-each select="ram:OccurrenceDateTime"> + <br/> + <span> + <xsl:text>* Leistungsdatum: </xsl:text> + </span> + <xsl:for-each select="udt:DateTimeString"> + <xsl:call-template name="ram:Datum"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeSettlement"> + <xsl:for-each select="ram:BillingSpecifiedPeriod"> + <br/> + <span> + <xsl:text>* Berechnungszeitraum: </xsl:text> + </span> + <xsl:for-each select="ram:StartDateTime"> + <xsl:for-each select="udt:DateTimeString"> + <xsl:call-template name="ram:Datum"/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:EndDateTime"> + <span> + <xsl:text> bis </xsl:text> + </span> + <xsl:for-each select="udt:DateTimeString"> + <xsl:call-template name="ram:Datum"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedTradeProduct"> + <xsl:for-each select="ram:OriginTradeCountry"> + <xsl:for-each select="ram:ID"> + <br/> + <span> + <xsl:text>* Herkunftsland: </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeDelivery"> + <xsl:for-each select="ram:PackageQuantity"> + <br/> + <span> + <xsl:text>* Anzahl Packstücke: </xsl:text> + </span> + <span> + <xsl:variable name="altova:seqContentStrings_21"> + <xsl:value-of select="format-number(number(string(.)), '##0', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_21" select="string($altova:seqContentStrings_21)"/> + <xsl:value-of select="$altova:sContent_21"/> + </span> + </xsl:for-each> + <xsl:call-template name="PackageQuantity"/> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeAgreement"> + <xsl:for-each select="ram:BuyerOrderReferencedDocument"> + <br/> + <span> + <xsl:text>* Bestellung</xsl:text> + </span> + <xsl:call-template name="ram:Positionsreferenz"/> + </xsl:for-each> + <xsl:for-each select="ram:ContractReferencedDocument"> + <br/> + <span> + <xsl:text>* Vertrag</xsl:text> + </span> + <xsl:call-template name="ram:Positionsreferenz"/> + </xsl:for-each> + <xsl:for-each select="ram:AdditionalReferencedDocument"> + <br/> + <span> + <xsl:text>* Dokument (</xsl:text> + </span> + <xsl:for-each select="ram:ReferenceTypeCode"> + <xsl:call-template name="ram:Referenz"/> + </xsl:for-each> + <span> + <xsl:text>)</xsl:text> + </span> + <xsl:call-template name="ram:Positionsreferenz"/> + </xsl:for-each> + <xsl:for-each select="ram:CustomerOrderReferencedDocument"> + <br/> + <span> + <xsl:text>* Kundenbestellung</xsl:text> + </span> + <xsl:call-template name="ram:Positionsreferenz"/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeDelivery"> + <xsl:for-each select="ram:DespatchAdviceReferencedDocument"> + <br/> + <span> + <xsl:text>* Lieferavis</xsl:text> + </span> + <xsl:call-template name="ram:Positionsreferenz"/> + </xsl:for-each> + <xsl:for-each select="ram:ReceivingAdviceReferencedDocument"> + <br/> + <span> + <xsl:text>* Wareneingang </xsl:text> + </span> + <xsl:call-template name="ram:Positionsreferenz"/> + </xsl:for-each> + <xsl:for-each select="ram:DeliveryNoteReferencedDocument"> + <br/> + <span> + <xsl:text>* Lieferschein</xsl:text> + </span> + <xsl:call-template name="ram:Positionsreferenz"/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeSettlement"> + <xsl:for-each select="ram:SpecifiedTradeAccountingAccount"> + <xsl:for-each select="ram:ID"> + <br/> + <span> + <xsl:text>* Buchungsreferenz: </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedTradeProduct"> + <xsl:for-each select="ram:DesignatedProductClassification"> + <br/> + <span> + <xsl:text>* Klassifikation: </xsl:text> + </span> + <xsl:for-each select="ram:ClassCode"> + <span> + <xsl:text>[</xsl:text> + </span> + <xsl:apply-templates/> + <span> + <xsl:text>] </xsl:text> + </span> + </xsl:for-each> + <xsl:for-each select="ram:ClassName"> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:ClassCode"> + <xsl:call-template name="Klassifikationsart"/> + <xsl:for-each select="@listVersionID"> + <span> + <xsl:text>, Version: </xsl:text> + </span> + <span> + <xsl:value-of select="string(.)"/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedSupplyChainTradeDelivery"> + <xsl:for-each select="ram:ShipToTradeParty"> + <br/> + <span style="text-decoration:underline; "> + <xsl:text>Abweichender Warenempfänger:</xsl:text> + </span> + <br/> + <xsl:call-template name="ram:Party"/> + </xsl:for-each> + <xsl:for-each select="ram:UltimateShipToTradeParty"> + <br/> + <span style="text-decoration:underline; "> + <xsl:text>Abweichender Endempfänger:</xsl:text> + </span> + <br/> + <xsl:call-template name="ram:Party"/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedTradeProduct"> + <xsl:if test="fn:exists(ram:ApplicableProductCharacteristic)"> + <br/> + <br/> + <span style="text-decoration:underline; "> + <xsl:text>Weitere Eigenschaften:</xsl:text> + </span> + <br/> + </xsl:if> + <xsl:for-each select="ram:ApplicableProductCharacteristic"> + <xsl:for-each select="ram:Description"> + <br/> + <xsl:apply-templates/> + </xsl:for-each> + <span> + <xsl:text>: </xsl:text> + </span> + <xsl:for-each select="ram:TypeCode"> + <xsl:apply-templates/> + </xsl:for-each> + <span> + <xsl:text> = </xsl:text> + </span> + <xsl:for-each select="ram:Value"> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:ValueMeasure"> + <xsl:call-template name="ram:Menge"/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:if test="fn:exists(ram:SpecifiedTradeProduct/ram:IncludedReferencedProduct)"> + <br/> + <br/> + <span style="text-decoration:underline; "> + <xsl:text>Basisartikel:</xsl:text> + </span> + <br/> + </xsl:if> + <xsl:for-each select="ram:SpecifiedTradeProduct"> + <xsl:if test="fn:exists(ram:IncludedReferencedProduct)"> + <xsl:variable name="altova:table"> + <table style="border:0px; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_22" select="."/> + <xsl:variable name="altova:ColumnData"/> + <thead> + <tr> + <th style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; text-align:left; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>Art-Nr-Kunde</xsl:text> + </span> + <br/> + </th> + <th style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>Art-Nr-Lief.</xsl:text> + </span> + </th> + <th style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; width:110px; "> + <span> + <xsl:text>Art-Nr. (Art)</xsl:text> + </span> + </th> + <th style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; "> + <span> + <xsl:text>Beschreibung</xsl:text> + </span> + </th> + <th style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; text-align:right; width:120px; "> + <span> + <xsl:text>Menge</xsl:text> + </span> + </th> + </tr> + </thead> + <tbody> + <xsl:for-each select="ram:IncludedReferencedProduct"> + <tr> + <td style="border-bottom-style:none; border-left-style:none; border-right-style:none; border-top-style:none; text-align:left; vertical-align:top; width:110px; "> + <xsl:for-each select="ram:BuyerAssignedID"> + <xsl:apply-templates/> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-left-style:none; border-right-style:none; border-top-style:none; vertical-align:top; width:110px; "> + <xsl:for-each select="ram:SellerAssignedID"> + <xsl:apply-templates/> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-left-style:none; border-right-style:none; border-top-style:none; vertical-align:top; width:110px; "> + <xsl:for-each select="ram:GlobalID"> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:GlobalID"> + <xsl:for-each select="@schemeID"> + <xsl:call-template name="ram:Global_Identifier"/> + </xsl:for-each> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-left-style:none; border-right-style:none; border-top-style:none; vertical-align:top; "> + <xsl:for-each select="ram:Name"> + <xsl:apply-templates/> + </xsl:for-each> + <br/> + <xsl:for-each select="ram:Description"> + <xsl:apply-templates/> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-left-style:none; border-right-style:none; border-top-style:none; text-align:right; vertical-align:top; width:120px; "> + <xsl:for-each select="ram:UnitQuantity"> + <xsl:call-template name="ram:Menge"/> + </xsl:for-each> + </td> + </tr> + </xsl:for-each> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + </xsl:for-each> + </td> + <td style="border-collapse:collapse; border-left-style:none; border-right-style:none; border-spacing:0px; border-top-style:none; empty-cells:hide; width:110px; "/> + </tr> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:for-each> + </xsl:for-each> + <br/> + </td> + </tr> + <tr> + <td style="border-bottom-style:none; border-top-style:none; "> + <xsl:if test="fn:exists(rsm:SpecifiedSupplyChainTradeTransaction/ram:ApplicableSupplyChainTradeSettlement/ram:SpecifiedTradePaymentTerms)"> + <br/> + <span style="empty-cells:hide; font-weight:bold; text-decoration:underline; "> + <xsl:text>Zahlungsbedingungen:</xsl:text> + </span> + <br/> + <br/> + <xsl:variable name="altova:table"> + <table style="border:0px; border-collapse:collapse; border-right-style:none; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_23" select="."/> + <xsl:variable name="altova:ColumnData"/> + <thead> + <tr> + <th style="border-left-style:none; "> + <span> + <xsl:text>Beschreibung</xsl:text> + </span> + </th> + <th style="width:110px; "> + <span> + <xsl:text>Fälligkeit</xsl:text> + </span> + </th> + <th style="border-right-style:none; width:110px; "> + <span> + <xsl:text>Teilzahlung</xsl:text> + </span> + </th> + </tr> + </thead> + <tbody> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"> + <xsl:for-each select="ram:SpecifiedTradePaymentTerms"> + <tr> + <td style="border-bottom-style:none; border-left-style:none; "> + <xsl:for-each select="ram:Description"> + <span style="white-space:pre-wrap; "> + <xsl:apply-templates/> + </span> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; text-align:center; width:110px; "> + <xsl:for-each select="ram:DueDateDateTime"> + <xsl:for-each select="udt:DateTimeString"> + <xsl:call-template name="ram:Datum"/> + </xsl:for-each> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-right-style:none; text-align:right; width:110px; "> + <xsl:for-each select="ram:PartialPaymentAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_24"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_24" select="string($altova:seqContentStrings_24)"/> + <xsl:value-of select="$altova:sContent_24"/> + </span> + </xsl:for-each> + </td> + </tr> + <tr> + <td colspan="3" style="border-left-style:none; border-right-style:none; border-top-style:none; min-height:0px; "> + <xsl:if test="fn:exists(ram:ApplicableTradePaymentPenaltyTerms) or fn:exists(ram:ApplicableTradePaymentDiscountTerms)"> + <xsl:variable name="altova:table"> + <table style="border:0px; border-collapse:collapse; border-left-style:none; border-top-style:none; margin:0px; padding:0px; " border="1" width="100%"> + <xsl:variable name="altova:CurrContextGrid_25" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <tr style="border-bottom-style:none; border-top-style:none; "> + <td style="border-bottom-style:none; border-left-style:none; border-top-style:none; min-height:0px; "/> + <td style="border-bottom-style:none; min-height:0px; text-align:center; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>Bezug</xsl:text> + </span> + </td> + <td style="border-bottom-style:none; min-height:0px; text-align:center; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>Innerhalb</xsl:text> + </span> + </td> + <td style="border-bottom-style:none; min-height:0px; text-align:center; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>Basisbetrag</xsl:text> + </span> + </td> + <td style="border-bottom-style:none; min-height:0px; text-align:center; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>%</xsl:text> + </span> + </td> + <td style="border-bottom-style:none; border-right-style:none; min-height:0px; text-align:center; width:108px; "> + <span style="font-weight:bold; "> + <xsl:text>Betrag</xsl:text> + </span> + </td> + </tr> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + <xsl:if test="fn:exists(ram:ApplicableTradePaymentPenaltyTerms)"> + <xsl:variable name="altova:table"> + <table style="border:0px; border-bottom-style:none; border-collapse:collapse; margin:0px; padding:0px; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_26" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <xsl:for-each select="ram:ApplicableTradePaymentPenaltyTerms"> + <tr> + <td style="border-bottom-style:none; border-left-style:none; min-height:0px; text-align:right; "> + <span> + <xsl:text>Zuschlag  </xsl:text> + </span> + </td> + <td style="border-bottom-style:none; min-height:0px; text-align:center; width:110px; "> + <xsl:for-each select="ram:BasisDateTime"> + <xsl:for-each select="udt:DateTimeString"> + <xsl:call-template name="ram:Datum"/> + </xsl:for-each> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; min-height:0px; text-align:right; width:110px; "> + <xsl:for-each select="ram:BasisPeriodMeasure"> + <xsl:call-template name="ram:Menge"/> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; min-height:0px; text-align:right; width:110px; "> + <xsl:for-each select="ram:BasisAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_27"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_27" select="string($altova:seqContentStrings_27)"/> + <xsl:value-of select="$altova:sContent_27"/> + </span> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; min-height:0px; text-align:right; width:110px; "> + <xsl:for-each select="ram:CalculationPercent"> + <span> + <xsl:variable name="altova:seqContentStrings_28"> + <xsl:value-of select="format-number(number(string(.)), '###.##0,####', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_28" select="string($altova:seqContentStrings_28)"/> + <xsl:value-of select="$altova:sContent_28"/> + </span> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-right-style:none; min-height:0px; text-align:right; width:108px; "> + <xsl:for-each select="ram:ActualPenaltyAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_29"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_29" select="string($altova:seqContentStrings_29)"/> + <xsl:value-of select="$altova:sContent_29"/> + </span> + </xsl:for-each> + </td> + </tr> + </xsl:for-each> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + <xsl:if test="fn:exists(ram:ApplicableTradePaymentDiscountTerms)"> + <xsl:variable name="altova:table"> + <table style="border:0px; border-collapse:collapse; margin:0px; padding:0px; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_30" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <xsl:for-each select="ram:ApplicableTradePaymentDiscountTerms"> + <tr> + <td style="border-bottom-style:none; border-left-style:none; min-height:0px; text-align:right; "> + <span> + <xsl:text>Skonto  </xsl:text> + </span> + </td> + <td style="border-bottom-style:none; min-height:0px; text-align:center; width:110px; "> + <xsl:for-each select="ram:BasisDateTime"> + <xsl:for-each select="udt:DateTimeString"> + <xsl:call-template name="ram:Datum"/> + </xsl:for-each> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; min-height:0px; text-align:right; width:110px; "> + <xsl:for-each select="ram:BasisPeriodMeasure"> + <xsl:call-template name="ram:Menge"/> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; min-height:0px; text-align:right; width:110px; "> + <xsl:for-each select="ram:BasisAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_31"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_31" select="string($altova:seqContentStrings_31)"/> + <xsl:value-of select="$altova:sContent_31"/> + </span> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; min-height:0px; text-align:right; width:110px; "> + <xsl:for-each select="ram:CalculationPercent"> + <span> + <xsl:variable name="altova:seqContentStrings_32"> + <xsl:value-of select="format-number(number(string(.)), '###.##0,####', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_32" select="string($altova:seqContentStrings_32)"/> + <xsl:value-of select="$altova:sContent_32"/> + </span> + </xsl:for-each> + </td> + <td style="border-bottom-style:none; border-right-style:none; min-height:0px; text-align:right; width:108px; "> + <xsl:for-each select="ram:ActualDiscountAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_33"> + <xsl:value-of select="format-number(number(-1 * .), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_33" select="string($altova:seqContentStrings_33)"/> + <xsl:value-of select="$altova:sContent_33"/> + </span> + </xsl:for-each> + </td> + </tr> + </xsl:for-each> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + </td> + </tr> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + <xsl:if test="fn:exists(rsm:SpecifiedSupplyChainTradeTransaction/ram:ApplicableSupplyChainTradeSettlement/ram:SpecifiedTradeSettlementPaymentMeans)"> + <br/> + <span style="font-weight:bold; text-decoration:underline; "> + <xsl:text>Zahlungsart:</xsl:text> + </span> + <br/> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"> + <xsl:for-each select="ram:SpecifiedTradeSettlementPaymentMeans"> + <xsl:for-each select="ram:Information"> + <br/> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:TypeCode"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Zahlungstyp (codiert): </xsl:text> + </span> + <xsl:call-template name="ram:PaymentType"/> + </xsl:for-each> + <xsl:for-each select="ram:ID"> + <xsl:for-each select="@schemeAgencyID"> + <br/> + <span> + <xsl:text>Gläubiger-ID         : </xsl:text> + </span> + <span> + <xsl:value-of select="string(.)"/> + </span> + </xsl:for-each> + <br/> + <span> + <xsl:text>Mandatsreferenz      : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:PayerPartyDebtorFinancialAccount"> + <xsl:for-each select="ram:IBANID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Käufer-IBAN          : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:ProprietaryID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Käufer-Kontonummer   : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:PayerSpecifiedDebtorFinancialInstitution"> + <xsl:for-each select="ram:BICID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Käufer-BIC           : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:GermanBankleitzahlID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Käufer-Bankleitzahl  : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:Name"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Käufer-Kreditinstitut: </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + <br/> + <xsl:for-each select="ram:PayeePartyCreditorFinancialAccount"> + <xsl:for-each select="ram:AccountName"> + <br/> + <span> + <xsl:text>Verkäufer-Kontoname  : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:IBANID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Verkäufer-IBAN       : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:ProprietaryID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Verkäufer-Kontonummer: </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:PayeeSpecifiedCreditorFinancialInstitution"> + <xsl:for-each select="ram:BICID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Verkäufer-BIC        : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:GermanBankleitzahlID"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Verkäufer-BLZ        : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:Name"> + <br/> + <span style="empty-cells:hide; "> + <xsl:text>Verkäufer-Kreditinst.: </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </xsl:if> + </td> + </tr> + <tr> + <td style="border-bottom-style:none; border-right-style:none; border-top-style:none; "> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"> + <br/> + <xsl:if test="fn:exists(ram:SpecifiedTradeAllowanceCharge) or fn:exists(ram:SpecifiedLogisticsServiceCharge)"> + <span style="font-weight:bold; text-decoration:underline; "> + <xsl:text>Zu- und Abschläge:</xsl:text> + </span> + <br/> + <br/> + <xsl:variable name="altova:table"> + <table style="border:0px; border-collapse:collapse; empty-cells:hide; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_34" select="."/> + <xsl:variable name="altova:ColumnData"/> + <thead> + <tr> + <th colspan="2" style="border-left-style:none; "> + <span> + <xsl:text>Art</xsl:text> + </span> + </th> + <th> + <span> + <xsl:text>%</xsl:text> + </span> + </th> + <th> + <span> + <xsl:text>Basisbetrag</xsl:text> + </span> + </th> + <th style="width:110px; "> + <span> + <xsl:text>Basismenge</xsl:text> + </span> + </th> + <th style="width:110px; "> + <span> + <xsl:text>Steuer</xsl:text> + </span> + </th> + <th style="border-right-style:none; width:110px; "> + <span> + <xsl:text>Betrag</xsl:text> + </span> + </th> + </tr> + </thead> + <tbody> + <xsl:for-each select="ram:SpecifiedTradeAllowanceCharge"> + <xsl:sort select="ram:SequenceNumeric" data-type="text" order="ascending"/> + <tr> + <td style="border-left-style:none; "> + <xsl:for-each select="ram:ChargeIndicator"> + <xsl:for-each select="udt:Indicator"> + <span> + <xsl:value-of select="if (. eq fn:true())then 'Zuschlag' else 'Abschlag'"/> + </span> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SequenceNumeric"> + <span> + <xsl:text> Nr. </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </td> + <td> + <xsl:for-each select="ram:Reason"> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:ReasonCode"> + <span> + <xsl:text> </xsl:text> + </span> + <xsl:call-template name="AllowanceChargeReasonCode"/> + </xsl:for-each> + </td> + <td style="text-align:right; "> + <xsl:for-each select="ram:CalculationPercent"> + <span> + <xsl:variable name="altova:seqContentStrings_35"> + <xsl:value-of select="format-number(number(string(.)), '###.##0,####', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_35" select="string($altova:seqContentStrings_35)"/> + <xsl:value-of select="$altova:sContent_35"/> + </span> + </xsl:for-each> + </td> + <td style="text-align:right; "> + <xsl:for-each select="ram:BasisAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_36"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_36" select="string($altova:seqContentStrings_36)"/> + <xsl:value-of select="$altova:sContent_36"/> + </span> + </xsl:for-each> + </td> + <td style="text-align:right; width:110px; "> + <xsl:for-each select="ram:BasisQuantity"> + <xsl:call-template name="ram:Menge"/> + </xsl:for-each> + </td> + <td style="text-align:right; width:110px; "> + <xsl:for-each select="ram:CategoryTradeTax"> + <xsl:call-template name="ram:TradeTax"/> + </xsl:for-each> + </td> + <td style="border-right-style:none; text-align:right; width:110px; "> + <xsl:for-each select="ram:ActualAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_37"> + <xsl:value-of select="format-number(number(if (../ram:ChargeIndicator/udt:Indicator eq fn:true()) then . else -1 * .), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_37" select="string($altova:seqContentStrings_37)"/> + <xsl:value-of select="$altova:sContent_37"/> + </span> + </xsl:for-each> + </td> + </tr> + </xsl:for-each> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + <xsl:if test="fn:exists(ram:SpecifiedLogisticsServiceCharge)"> + <xsl:if test="fn:not(fn:exists(ram:SpecifiedTradeAllowanceCharge))"> + <xsl:variable name="altova:table"> + <table style="border:0px; border-top-style:none; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_38" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <xsl:for-each select="ram:SpecifiedLogisticsServiceCharge"> + <tr> + <td style="border-left-style:none; border-top-style:solid; text-align:center; "> + <span style="font-weight:bold; "> + <xsl:text>Art</xsl:text> + </span> + </td> + <td style="border-top-style:solid; text-align:center; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>Steuer</xsl:text> + </span> + </td> + <td style="border-right-style:none; border-top-style:solid; text-align:center; width:110px; "> + <span style="font-weight:bold; "> + <xsl:text>Betrag</xsl:text> + </span> + </td> + </tr> + </xsl:for-each> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + <xsl:variable name="altova:table"> + <table style="border:0px; border-top-style:none; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_39" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <xsl:for-each select="ram:SpecifiedLogisticsServiceCharge"> + <tr> + <td style="border-left-style:none; border-top-style:none; "> + <xsl:for-each select="ram:Description"> + <span style="white-space:pre-wrap; "> + <xsl:apply-templates/> + </span> + </xsl:for-each> + </td> + <td style="border-top-style:none; text-align:right; width:110px; "> + <xsl:for-each select="ram:AppliedTradeTax"> + <xsl:call-template name="ram:TradeTax"/> + </xsl:for-each> + </td> + <td style="border-right-style:none; border-top-style:none; text-align:right; width:110px; "> + <xsl:for-each select="ram:AppliedAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_40"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_40" select="string($altova:seqContentStrings_40)"/> + <xsl:value-of select="$altova:sContent_40"/> + </span> + </xsl:for-each> + </td> + </tr> + </xsl:for-each> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + </xsl:if> + <br/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"/> + </xsl:for-each> + </td> + </tr> + <tr> + <td style="border-bottom-style:none; border-top-style:none; "> + <xsl:if test="fn:exists(rsm:SpecifiedSupplyChainTradeTransaction/ram:ApplicableSupplyChainTradeSettlement/ram:ApplicableTradeTax)"> + <br/> + <span style="font-weight:bold; text-decoration:underline; "> + <xsl:text>Steuern:</xsl:text> + </span> + <br/> + <br/> + <xsl:variable name="altova:table"> + <table style="border:0px; border-collapse:collapse; border-right-style:none; width:100%; " border="1"> + <xsl:variable name="altova:CurrContextGrid_41" select="."/> + <xsl:variable name="altova:ColumnData"/> + <thead> + <tr> + <th style="border-left-style:none; "> + <span> + <xsl:text>Art (Kategorie)</xsl:text> + </span> + </th> + <th> + <span> + <xsl:text>Warenwert</xsl:text> + </span> + </th> + <th> + <span> + <xsl:text>Zu-/Abschlag</xsl:text> + </span> + </th> + <th style="width:110px; "> + <span> + <xsl:text>Nettobetrag</xsl:text> + </span> + </th> + <th style="width:110px; "> + <span> + <xsl:text>USt. %</xsl:text> + </span> + </th> + <th style="border-right-style:none; width:110px; "> + <span> + <xsl:text>USt.-Betrag</xsl:text> + </span> + </th> + </tr> + </thead> + <tbody> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"> + <xsl:for-each select="ram:ApplicableTradeTax"> + <tr> + <td style="border-left-style:none; "> + <xsl:for-each select="ram:TypeCode"> + <xsl:apply-templates/> + </xsl:for-each> + <span> + <xsl:text> </xsl:text> + </span> + <xsl:for-each select="ram:CategoryCode"> + <span> + <xsl:text>(</xsl:text> + </span> + <xsl:apply-templates/> + <span> + <xsl:text>)</xsl:text> + </span> + </xsl:for-each> + <xsl:for-each select="ram:ExemptionReason"> + <br/> + <xsl:apply-templates/> + </xsl:for-each> + </td> + <td style="text-align:right; "> + <xsl:for-each select="ram:LineTotalBasisAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_42"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_42" select="string($altova:seqContentStrings_42)"/> + <xsl:value-of select="$altova:sContent_42"/> + </span> + </xsl:for-each> + </td> + <td style="text-align:right; "> + <xsl:for-each select="ram:AllowanceChargeBasisAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_43"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_43" select="string($altova:seqContentStrings_43)"/> + <xsl:value-of select="$altova:sContent_43"/> + </span> + </xsl:for-each> + </td> + <td style="text-align:right; width:110px; "> + <xsl:for-each select="ram:BasisAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_44"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_44" select="string($altova:seqContentStrings_44)"/> + <xsl:value-of select="$altova:sContent_44"/> + </span> + </xsl:for-each> + </td> + <td style="text-align:right; width:110px; "> + <xsl:for-each select="ram:ApplicablePercent"> + <span> + <xsl:variable name="altova:seqContentStrings_45"> + <xsl:value-of select="format-number(number(string(.)), '###.##0,####', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_45" select="string($altova:seqContentStrings_45)"/> + <xsl:value-of select="$altova:sContent_45"/> + </span> + </xsl:for-each> + </td> + <td style="border-right-style:none; text-align:right; width:110px; "> + <xsl:for-each select="ram:CalculatedAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_46"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_46" select="string($altova:seqContentStrings_46)"/> + <xsl:value-of select="$altova:sContent_46"/> + </span> + </xsl:for-each> + </td> + </tr> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:if> + </td> + </tr> + <tr> + <td style="border-bottom-style:none; text-align:left; "> + <br/> + <span style="font-weight:bold; text-decoration:underline; "> + <xsl:text>Belegsummen:</xsl:text> + </span> + <br/> + <xsl:for-each select="rsm:SpecifiedSupplyChainTradeTransaction"> + <xsl:for-each select="ram:ApplicableSupplyChainTradeSettlement"> + <xsl:for-each select="ram:SpecifiedTradeSettlementMonetarySummation"> + <xsl:variable name="altova:table"> + <table style="border:0px; " border="1" width="100%"> + <xsl:variable name="altova:CurrContextGrid_47" select="."/> + <xsl:variable name="altova:ColumnData"/> + <tbody> + <tr> + <td style="border-style:none; "/> + <td style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; padding:1px; text-align:left; width:220px; "> + <span style="font-weight:bold; "> + <xsl:text>Positionssumme</xsl:text> + </span> + </td> + <td style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; padding:1px; text-align:right; width:110px; "> + <xsl:for-each select="ram:LineTotalAmount"> + <span style="font-weight:bold; "> + <xsl:variable name="altova:seqContentStrings_48"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_48" select="string($altova:seqContentStrings_48)"/> + <xsl:value-of select="$altova:sContent_48"/> + </span> + </xsl:for-each> + </td> + </tr> + <tr> + <td style="border-style:none; "/> + <td style="border:0px; border-top-style:double; padding:1px; text-align:left; width:220px; "> + <span> + <xsl:text>Gesamtbetrag der Zuschläge</xsl:text> + </span> + </td> + <td style="border:0px; border-top-style:double; padding:1px; text-align:right; width:110px; "> + <xsl:for-each select="ram:ChargeTotalAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_49"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_49" select="string($altova:seqContentStrings_49)"/> + <xsl:value-of select="$altova:sContent_49"/> + </span> + </xsl:for-each> + </td> + </tr> + <tr> + <td style="border-style:none; "/> + <td style="border:0px; border-top-style:double; padding:1px; text-align:left; width:220px; "> + <span> + <xsl:text>Gesamtbetrag der Abschläge</xsl:text> + </span> + </td> + <td style="border:0px; border-top-style:double; padding:1px; text-align:right; width:110px; "> + <xsl:for-each select="ram:AllowanceTotalAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_50"> + <xsl:value-of select="format-number(number(-1*.), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_50" select="string($altova:seqContentStrings_50)"/> + <xsl:value-of select="$altova:sContent_50"/> + </span> + </xsl:for-each> + </td> + </tr> + <tr> + <td style="border-style:none; "/> + <td style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; padding:1px; text-align:left; width:220px; "> + <span style="font-weight:bold; "> + <xsl:text>Rechnungssumme ohne USt.</xsl:text> + </span> + </td> + <td style="border-bottom-style:solid; border-left-style:none; border-right-style:none; border-top-style:none; padding:1px; text-align:right; width:110px; "> + <xsl:for-each select="ram:TaxBasisTotalAmount"> + <span style="font-weight:bold; "> + <xsl:variable name="altova:seqContentStrings_51"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_51" select="string($altova:seqContentStrings_51)"/> + <xsl:value-of select="$altova:sContent_51"/> + </span> + </xsl:for-each> + </td> + </tr> + <tr> + <td style="border-style:none; "/> + <td style="border:0px; border-top-style:double; padding:1px; text-align:left; width:220px; "> + <span> + <xsl:text>Steuerbetrag</xsl:text> + </span> + </td> + <td style="border:0px; border-top-style:double; padding:1px; text-align:right; width:110px; "> + <xsl:for-each select="ram:TaxTotalAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_52"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_52" select="string($altova:seqContentStrings_52)"/> + <xsl:value-of select="$altova:sContent_52"/> + </span> + </xsl:for-each> + </td> + </tr> + <tr> + <td style="border-style:none; "/> + <td style="border-bottom-style:double; border-bottom-width:medium; border-left-style:none; border-right-style:none; border-top-style:none; padding:1px; text-align:left; width:220px; "> + <span style="font-weight:bold; "> + <xsl:text>Bruttosumme</xsl:text> + </span> + </td> + <td style="border-bottom-style:double; border-bottom-width:medium; border-left-style:none; border-right-style:none; border-top-style:none; padding:1px; text-align:right; width:110px; "> + <xsl:for-each select="ram:GrandTotalAmount"> + <span style="font-weight:bold; "> + <xsl:variable name="altova:seqContentStrings_53"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_53" select="string($altova:seqContentStrings_53)"/> + <xsl:value-of select="$altova:sContent_53"/> + </span> + </xsl:for-each> + </td> + </tr> + <tr> + <td style="border-style:none; "/> + <td style="border:0px; border-top-style:double; padding:1px; text-align:left; width:220px; "> + <xsl:if test="(ram:TotalPrepaidAmount>=0 and fn:exists(ram:TotalPrepaidAmount)) or(fn:not(fn:exists(ram:TotalPrepaidAmount)) and fn:not(ends-with( ../../../rsm:SpecifiedExchangedDocumentContext/ram:GuidelineSpecifiedDocumentContextParameter/ram:ID , 'basic' )))"> + <span> + <xsl:text>Erhaltene Anzahlungen</xsl:text> + </span> + <br/> + </xsl:if> + <xsl:if test="ram:TotalPrepaidAmount<0 and fn:exists(ram:TotalPrepaidAmount)"> + <span> + <xsl:text>Offene Zahlungen</xsl:text> + </span> + <br/> + </xsl:if> + </td> + <td style="border:0px; border-top-style:double; padding:1px; text-align:right; width:110px; "> + <xsl:if test="fn:exists(TotalPrepaidAmount) or fn:not(ends-with( ../../../rsm:SpecifiedExchangedDocumentContext/ram:GuidelineSpecifiedDocumentContextParameter/ram:ID , 'basic' ))"> + <xsl:for-each select="ram:TotalPrepaidAmount"> + <span> + <xsl:variable name="altova:seqContentStrings_54"> + <xsl:value-of select="format-number(number(-1*.), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_54" select="string($altova:seqContentStrings_54)"/> + <xsl:value-of select="$altova:sContent_54"/> + </span> + </xsl:for-each> + </xsl:if> + </td> + </tr> + <tr> + <td style="border-style:none; "/> + <td style="border:0px; border-top-style:double; padding:1px; text-align:left; width:220px; "> + <xsl:if test="fn:exists(ram:DuePayableAmount) or fn:not(ends-with( ../../../rsm:SpecifiedExchangedDocumentContext/GuidelineSpecifiedDocumentContextParameter/ID , 'basic' ))"> + <span style="font-weight:bold; "> + <xsl:text>Zahlbetrag</xsl:text> + </span> + </xsl:if> + </td> + <td style="border:0px; border-top-style:double; padding:1px; text-align:right; width:110px; "> + <xsl:if test="fn:exists(ram:DuePayableAmount) or fn:not(ends-with( ../../../rsm:SpecifiedExchangedDocumentContext/GuidelineSpecifiedDocumentContextParameter/ID , 'basic' ))"> + <xsl:for-each select="ram:DuePayableAmount"> + <span style="font-weight:bold; "> + <xsl:variable name="altova:seqContentStrings_55"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_55" select="string($altova:seqContentStrings_55)"/> + <xsl:value-of select="$altova:sContent_55"/> + </span> + </xsl:for-each> + </xsl:if> + </td> + </tr> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + </td> + </tr> + </tbody> + </table> + </xsl:variable> + <xsl:variable name="altova:col-count" select="sum( for $altova:cell in $altova:table/table/(thead | tbody | tfoot)[ 1 ]/tr[ 1 ]/(th | td) return altova:col-span( $altova:cell ) )"/> + <xsl:variable name="altova:generate-cols" as="xs:boolean*" select="for $altova:pos in 1 to $altova:col-count return true()"/> + <xsl:apply-templates select="$altova:table" mode="altova:generate-table"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + <br/> + </xsl:for-each> + </xsl:for-each> + <br/> + <br/> + </body> + </html> + </xsl:template> + <xsl:template name="ram:Party"> + <xsl:for-each select="ram:ID"> + <span> + <xsl:text>Nummer        : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="@schemeID"> + <xsl:call-template name="local_Identifier"/> + </xsl:for-each> + <xsl:for-each select="ram:GlobalID"> + <br/> + <span> + <xsl:text>Globale Nummer: </xsl:text> + </span> + <xsl:apply-templates/> + <xsl:for-each select="@schemeID"> + <span> + <xsl:text> </xsl:text> + </span> + <xsl:call-template name="ram:Global_Identifier"/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:Name"> + <br/> + <span style="font-weight:bold; white-space:pre-wrap; "> + <xsl:apply-templates/> + </span> + </xsl:for-each> + <xsl:for-each select="ram:DefinedTradeContact"> + <xsl:for-each select="ram:PersonName"> + <br/> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:DepartmentName"> + <br/> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:PostalTradeAddress"> + <xsl:for-each select="ram:LineOne"> + <br/> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:LineTwo"> + <br/> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:CountryID"> + <br/> + <xsl:apply-templates/> + <span> + <xsl:text> </xsl:text> + </span> + </xsl:for-each> + <xsl:for-each select="ram:PostcodeCode"> + <xsl:apply-templates/> + <span> + <xsl:text> </xsl:text> + </span> + </xsl:for-each> + <xsl:for-each select="ram:CityName"> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + <br/> + <xsl:for-each select="ram:DefinedTradeContact"> + <xsl:for-each select="ram:TelephoneUniversalCommunication"> + <xsl:for-each select="ram:CompleteNumber"> + <br/> + <span> + <xsl:text>Telefon      : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:FaxUniversalCommunication"> + <xsl:for-each select="ram:CompleteNumber"> + <br/> + <span> + <xsl:text>Fax          : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:EmailURIUniversalCommunication"> + <xsl:for-each select="ram:URIID"> + <br/> + <span> + <xsl:text>E-Mail       : </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:for-each> + </xsl:for-each> + <xsl:for-each select="ram:SpecifiedTaxRegistration"> + <xsl:for-each select="ram:ID"> + <br/> + <xsl:call-template name="ram:TaxRegistration"/> + </xsl:for-each> + </xsl:for-each> + <br/> + </xsl:template> + <xsl:template name="ram:TradeTax"> + <xsl:for-each select="ram:ApplicablePercent"> + <span> + <xsl:variable name="altova:seqContentStrings_56"> + <xsl:value-of select="format-number(number(string(.)), '###.##0,####', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_56" select="string($altova:seqContentStrings_56)"/> + <xsl:value-of select="$altova:sContent_56"/> + </span> + <span> + <xsl:text> %</xsl:text> + </span> + </xsl:for-each> + <xsl:for-each select="ram:TypeCode"> + <span> + <xsl:text> </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:CategoryCode"> + <span> + <xsl:text> (</xsl:text> + </span> + <xsl:apply-templates/> + <span> + <xsl:text>)</xsl:text> + </span> + </xsl:for-each> + <xsl:for-each select="ram:CalculatedAmount"> + <span> + <xsl:text> entspricht </xsl:text> + </span> + <span> + <xsl:variable name="altova:seqContentStrings_57"> + <xsl:value-of select="format-number(number(string(.)), '##0,00', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_57" select="string($altova:seqContentStrings_57)"/> + <xsl:value-of select="$altova:sContent_57"/> + </span> + </xsl:for-each> + <xsl:for-each select="ram:ExemptionReason"> + <br/> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:template> + <xsl:template name="ram:Positionsreferenz"> + <xsl:for-each select="ram:ID"> + <span> + <xsl:text> Nr. </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + <xsl:for-each select="ram:IssueDateTime"> + <span> + <xsl:text> vom </xsl:text> + </span> + <span> + <xsl:variable name="altova:seqContentStrings_58"> + <xsl:value-of select="format-number(number(substring(string(string(.)), 9, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(.)), 6, 2)), '00', 'format1')"/> + <xsl:variable name="sText" as="xs:string?"> + <xsl:text>. </xsl:text> + </xsl:variable> + <xsl:value-of select="$sText"/> + <xsl:value-of select="format-number(number(substring(string(string(string(.))), 1, 4)), '0000', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_58" select="string($altova:seqContentStrings_58)"/> + <xsl:value-of select="$altova:sContent_58"/> + </span> + </xsl:for-each> + <xsl:for-each select="ram:LineID"> + <span> + <xsl:text> Zeile </xsl:text> + </span> + <xsl:apply-templates/> + </xsl:for-each> + </xsl:template> + <xsl:template name="ram:Datum"> + <span> + <xsl:value-of select="if ( @format = '102') then concat(substring(.,7,2),'.',substring(.,5,2),'.',substring(.,1,4)) else +if ( @format = '610') then concat(substring(.,5,2),'-',substring(.,1,4)) else +if ( @format = '616') then concat('KW ',substring(.,5,2),' ',substring(.,1,4)) else +concat('Ungültiges Datumsformat für: ', .)"/> + </span> + </xsl:template> + <xsl:template name="ram:Versand_Identifer"> + <span> + <xsl:value-of select="if(. eq 'GSIN') then . else +if(. eq 'GINC') then . else +if(. eq 'SSCC') then 'Nummer der Versandeinheit' else +if(. eq 'FLIGHT_NO') then 'Flugnummer' else +if(. eq 'NUMBER_PLATE') then 'Nummernschild' else +if(. eq 'SHIPMENT_REFERENCE') then 'Sendungs-/Ladungsbezugsnummer' else +."/> + </span> + </xsl:template> + <xsl:template name="ram:Global_Identifier"> + <span> + <xsl:text>(</xsl:text> + </span> + <span> + <xsl:value-of select="if (. eq '0021') then 'BIC' else +if (. eq '0060') then 'DUNS' else +if (. eq '0088') then 'GTIN' else +if (. eq '0160') then 'GLN' else +if (. eq '0177') then 'OSCAR' else +."/> + </span> + <span> + <xsl:text>)</xsl:text> + </span> + </xsl:template> + <xsl:template name="ram:Menge"> + <span> + <xsl:variable name="altova:seqContentStrings_59"> + <xsl:value-of select="format-number(number(string(.)), '##0', 'format1')"/> + </xsl:variable> + <xsl:variable name="altova:sContent_59" select="string($altova:seqContentStrings_59)"/> + <xsl:value-of select="$altova:sContent_59"/> + </span> + <xsl:for-each select="@unitCode"> + <span> + <xsl:text> </xsl:text> + </span> + <span> + <xsl:value-of select="if (. eq 'C62') then 'Stk' else +if (. eq 'DAY') then 'Tag(e)' else +if (. eq 'HAR') then 'ha' else +if (. eq 'HUR') then 'Std' else +if (. eq 'KGM') then 'kg' else +if (. eq 'KTM') then 'km' else +if (. eq 'LS') then 'pausch' else +if (. eq 'LTR') then 'l' else +if (. eq 'MIN') then 'min' else +if (. eq 'MMK') then 'mm²' else +if (. eq 'MMT') then 'mm' else +if (. eq 'MTK') then 'm²' else +if (. eq 'MTQ') then 'm³' else +if (. eq 'MTR') then 'm' else +if (. eq 'NAR') then 'Anz' else +if (. eq 'NPR') then 'Paar' else +if (. eq 'P1') then '%' else +if (. eq 'SET') then 'Set' else +if (. eq 'TNE') then 't' else +if (. eq 'WEE') then 'Woche(n)' else +."/> + </span> + </xsl:for-each> + </xsl:template> + <xsl:template name="ram:TaxRegistration"> + <span> + <xsl:value-of select="if ( @schemeID = 'FC') then concat('Steuernummer : ', .) else +if ( @schemeID = 'VA') then concat('USt.-Id.-Nr. : ', .) else +concat('Unbekannte Steuernummer (', @schemeID , '): ', .)"/> + </span> + </xsl:template> + <xsl:template name="ram:VersandMode"> + <span> + <xsl:value-of select="if (. eq '0')then '0 - Nicht spezifiziert' else +if (. eq '1')then '1 - Seefracht' else +if (. eq '2')then '2 - Schiene' else +if (. eq '3')then '3 - Straße' else +if (. eq '4')then '4 - Luftfracht' else +if (. eq '5')then '5 - Post/Paketversand' else +if (. eq '6')then '6 - Multimodaler Transport/kombinierter Verkehr' else +if (. eq '7')then '7 - Feste Transportinstallation' else +if (. eq '8')then '8 - Transport auf Binnengewässern' else +if (. eq '9')then '9 - Nicht anwendbar' else +fn:concat(.,' - unbekannte Transportart')"/> + </span> + </xsl:template> + <xsl:template name="ram:PaymentType"> + <span> + <xsl:value-of select="if(. eq '1') then concat(.,' - nicht definiert') else +if(. eq '3') then concat(.,' - Belastung durch automatisierte Clearingstelle') else +if(. eq '10') then concat(.,' - Barzahlung') else +if(. eq '20') then concat(.,' - per Scheck') else +if(. eq '31') then concat(.,' - per Überweisung (SEPA)') else +if(. eq '42') then concat(.,' - per Überweisung (nicht SEPA)') else +if(. eq '48') then concat(.,' - per Kreditkarte') else +if(. eq '49') then concat(.,' - per Lastschrift') else +if(. eq '97') then concat(.,' - per Ausgleich zwischen Partnern') else +."/> + </span> + </xsl:template> + <xsl:template name="ram:Referenz"> + <span> + <xsl:value-of select="if (. eq 'AAA')then 'Auftragsbestätigung' else +if (. eq 'AAB')then 'Proforma-Rechnung' else +if (. eq 'AAG') then 'Angebot' else +if (. eq 'AAJ') then 'Lieferauftrag' else +if (. eq 'AAL') then 'Zeichnung' else +if (. eq 'AAM') then 'Frachtbrief' else +if (. eq 'AAS') then 'Transportdokument' else +if (. eq 'ABT') then 'Zollerklärung' else +if (. eq 'AER') then 'Projektspezifikation' else +if (. eq 'AGG') then 'Reklamation' else +if (. eq 'AJS') then 'Vereinbarung' else +if (. eq 'ALO') then 'Wareneingang' else +if (. eq 'ALQ') then 'Rücksendungsanzeige' else +if (. eq 'API') then 'Bestandsbericht' else +if (. eq 'ASI') then 'Abliefernachweis' else +if (. eq 'AUD') then 'Inkasso-Referenz' else +if (. eq 'AWR') then 'Ursprungsbeleg' else +if (. eq 'BO') then 'Rahmenauftrag' else +if (. eq 'BC') then 'Vertrag (Käufer)' else +if (. eq 'CD') then 'Gutschrift' else +if (. eq 'DL') then 'Belastungsanzeige' else +if (. eq 'MG') then 'Zählernummer' else +if (. eq 'OI') then 'Vorherige Rechnung' else +if (. eq 'PK') then 'Packliste' else +if (. eq 'PL') then 'Preisliste' else +if (. eq 'POR') then 'Bestellantwort' else +if (. eq 'PP') then 'Bestelländerung' else +if (. eq 'TIN') then 'Transportauftrag' else +if (. eq 'VN') then 'Auftragsnummer (Lieferant)' else +."/> + </span> + </xsl:template> + <xsl:template name="PackageQuantity"> + <xsl:for-each select="ram:PackageQuantity"> + <xsl:for-each select="@unitCode"> + <span> + <xsl:text> </xsl:text> + </span> + <span> + <xsl:value-of select="if (. eq 'BA') then 'Tonne' else +if (. eq 'BC') then 'Getränkekiste' else +if (. eq 'BG') then 'Tüte, Beutel' else +if (. eq 'BO') then 'Flasche' else +if (. eq 'BX') then 'Schachtel' else +if (. eq 'CS') then 'Kiste' else +if (. eq 'CT') then 'Karton' else +if (. eq 'CX') then 'Dose' else +if (. eq 'NE') then 'Unverpackt oder ausgepackt' else +if (. eq 'PX') then 'Palette' else +if (. eq 'RO') then 'Rolle' else +if (. eq 'SA') then 'Sack' +else ."/> + </span> + </xsl:for-each> + </xsl:for-each> + </xsl:template> + <xsl:template name="local_Identifier"> + <span> + <xsl:text>(</xsl:text> + </span> + <xsl:choose> + <xsl:when test=". instance of element()"> + <xsl:apply-templates/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="."/> + </xsl:otherwise> + </xsl:choose> + <span> + <xsl:text>)</xsl:text> + </span> + </xsl:template> + <xsl:template name="Klassifikationsart"> + <xsl:for-each select="@listID"> + <span> + <xsl:text>, Art: </xsl:text> + </span> + <span> + <xsl:value-of select="if (. eq 'GPC') then 'Global Product Classification (GS1)' else +if (. eq 'ECL') then 'eCl@ass' else +if (. eq 'UNSPSC') then 'United Nations Standard Products and Services Code® (UNSPSC®)' else +if (. eq 'HS') then 'Zolltarifnummer (Harmonised System)' else +if (. eq 'CBV') then 'Gemeinsames Vokabular für öffentliche Aufträge (Common Procurement Vocabulary - CPV)' else +if (. eq 'SELLER_ASSIGNED') then 'vom Verkäufer vergeben' else +if (. eq 'BUYER_ASSIGNED') then 'vom Käufer vergeben' else +."/> + </span> + </xsl:for-each> + </xsl:template> + <xsl:template name="DeliveryTypeCode"> + <span> + <xsl:value-of select="if (. eq 'XW') then 'ab Werk' else +if (. eq 'FCA') then 'frei Frachtführer' else +if (. eq 'FAS') then 'frei längsseits Schiff' else +if (. eq 'FOB') then 'frei an Bord' else +if (. eq 'CFR') then 'Kosten und Fracht' else +if (. eq 'CIF') then 'Kosten, Versicherung und Fracht bis zum Bestimmungshafen' else +if (. eq 'DAT') then 'geliefert Terminal' else +if (. eq 'DAP') then 'geliefert benannter Ort' else +if (. eq 'CPT') then 'Fracht bezahlt bis' else +if (. eq 'CIP') then 'Fracht und Versicherung bezahlt' else +if (. eq 'DDP') then 'geliefert Zoll bezahlt' else +."/> + </span> + </xsl:template> + <xsl:template name="AllowanceChargeReasonCode"> + <span> + <xsl:text>(</xsl:text> + </span> + <span> + <xsl:value-of select="if (. eq 'AA') then 'Werbekostenzuschuß' else +if (. eq 'ADR') then 'Andere Dienste' else +if (. eq 'AEO') then 'Sammel- und Recyclingservice' else +if (. eq 'DI') then 'Abzug (Rabatt)' else +if (. eq 'EAB') then 'Skonto' else +if (. eq 'FC') then 'Frachtgebühren' else +if (. eq 'IN') then 'Versicherung' else +if (. eq 'MAC') then 'Mindermengenzuschlag' else +if (. eq 'NAA') then 'Einwegbehälter' else +if (. eq 'PC') then 'Verpacken' else +if (. eq 'RAA') then 'Rückvergütung' else +if (. eq 'SH') then 'Spezielle Handhabungsdienstleistungen' else +."/> + </span> + <span> + <xsl:text>)</xsl:text> + </span> + </xsl:template> + <xsl:function name="altova:is-cell-empty" as="xs:boolean"> + <xsl:param name="altova:cell" as="element()"/> + <xsl:sequence select="altova:is-node-empty( $altova:cell )"/> + </xsl:function> + <xsl:function name="altova:is-node-empty" as="xs:boolean"> + <xsl:param name="altova:node" as="element()"/> + <xsl:sequence select="every $altova:child in $altova:node/child::node() satisfies ( ( boolean( $altova:child/self::text() ) and string-length( $altova:child ) = 0 ) or ( ( boolean( $altova:child/self::div ) or boolean( $altova:child/self::span ) or boolean( $altova:child/self::a ) ) and altova:is-node-empty( $altova:child ) ) )"/> + </xsl:function> + <xsl:function name="altova:col-span" as="xs:integer"> + <xsl:param name="altova:cell" as="element()"/> + <xsl:sequence select="if ( exists( $altova:cell/@colspan ) ) then xs:integer( $altova:cell/@colspan ) else 1"/> + </xsl:function> + <xsl:template match="@* | node()" mode="altova:generate-table"> + <xsl:param name="altova:generate-cols"/> + <xsl:copy> + <xsl:apply-templates select="@* | node()" mode="#current"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:copy> + </xsl:template> + <xsl:template match="tbody" mode="altova:generate-table"> + <xsl:param name="altova:generate-cols"/> + <xsl:choose> + <xsl:when test="empty(tr)"> + <xsl:copy> + <tr> + <td/> + </tr> + </xsl:copy> + </xsl:when> + <xsl:otherwise> + <xsl:copy> + <xsl:apply-templates select="@* | node()" mode="#current"> + <xsl:with-param name="altova:generate-cols" select="$altova:generate-cols"/> + </xsl:apply-templates> + </xsl:copy> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + <xsl:template match="th | td" mode="altova:generate-table"> + <xsl:choose> + <xsl:when test="altova:is-cell-empty( . )"> + <xsl:copy> + <xsl:apply-templates select="@*" mode="#current"/> + <xsl:text> </xsl:text> + </xsl:copy> + </xsl:when> + <xsl:otherwise> + <xsl:copy> + <xsl:apply-templates select="@* | node()" mode="#current"/> + </xsl:copy> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + <xsl:function name="altova:GetChartYValuesForSingleSeries"> + <xsl:param name="seqCategoryLeafPos" as="node()*"/> + <xsl:param name="nodeSeriesLeafPos" as="node()"/> + <xsl:param name="bValuesInCategory" as="xs:boolean"/> + <xsl:for-each select="$seqCategoryLeafPos"> + <xsl:element name="altova:Value"> + <xsl:value-of select="altova:GetChartYValueForSingleSeriesPos($nodeSeriesLeafPos, ., $bValuesInCategory)"/> + </xsl:element> + </xsl:for-each> + </xsl:function> + <xsl:function name="altova:GetChartYValueForSingleSeriesPos"> + <xsl:param name="nodeSeriesLeafPos" as="node()"/> + <xsl:param name="nodeCategoryLeafPos" as="node()"/> + <xsl:param name="bValuesInCategory" as="xs:boolean"/> + <xsl:variable name="altova:seqCategoryContextIds" select="$nodeCategoryLeafPos/altova:Context/@altova:ContextId" as="xs:string*"/> + <xsl:variable name="altova:seqSeriesContextIds" select="$nodeSeriesLeafPos/altova:Context/@altova:ContextId" as="xs:string*"/> + <xsl:variable name="altova:sCommonContextId" select="for $i in $altova:seqCategoryContextIds return if (some $j in $altova:seqSeriesContextIds satisfies $i eq $j) then $i else ()" as="xs:string*"/> + <xsl:choose> + <xsl:when test="count($altova:sCommonContextId) gt 1"> + <xsl:message select="concat('Es wurden mehrere Werte anstatt eines einzigen gefunden (Contexts: ', string-join($altova:sCommonContextId, ', '), ').')" terminate="yes"/> + </xsl:when> + <xsl:when test="count($altova:sCommonContextId) lt 1"> + <xsl:message select="concat('XBRL Chart: Info: No value found for position labeled "', $nodeCategoryLeafPos/@altova:sLabel, '"')" terminate="no"/> + <xsl:sequence select="'altova:no-value'"/> + </xsl:when> + <xsl:when test="$bValuesInCategory"> + <xsl:sequence select="xs:string($nodeCategoryLeafPos/altova:Context[@altova:ContextId eq $altova:sCommonContextId]/@altova:Value)"/> + </xsl:when> + <xsl:otherwise> + <xsl:sequence select="xs:string($nodeSeriesLeafPos/altova:Context[@altova:ContextId eq $altova:sCommonContextId]/@altova:Value)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:function> + <xsl:function name="altova:GetChartLabelForPos" as="xs:string"> + <xsl:param name="nodeParam" as="node()"/> + <xsl:value-of select="string-join($nodeParam/ancestor-or-self::altova:Pos/@altova:sLabel, ' ')"/> + </xsl:function> + <xsl:function name="altova:convert-length-to-pixel" as="xs:decimal"> + <xsl:param name="altova:length"/> + <xsl:variable name="normLength" select="normalize-space($altova:length)"/> + <xsl:choose> + <xsl:when test="ends-with($normLength, 'px')"> + <xsl:value-of select="substring-before($normLength, 'px')"/> + </xsl:when> + <xsl:when test="ends-with($normLength, 'in')"> + <xsl:value-of select="xs:decimal(substring-before($normLength, 'in')) * $altova:nPxPerIn"/> + </xsl:when> + <xsl:when test="ends-with($normLength, 'cm')"> + <xsl:value-of select="xs:decimal(substring-before($normLength, 'cm')) * $altova:nPxPerIn div 2.54"/> + </xsl:when> + <xsl:when test="ends-with($normLength, 'mm')"> + <xsl:value-of select="xs:decimal(substring-before($normLength, 'mm')) * $altova:nPxPerIn div 25.4"/> + </xsl:when> + <xsl:when test="ends-with($normLength, 'pt')"> + <xsl:value-of select="xs:decimal(substring-before($normLength, 'pt')) * $altova:nPxPerIn div 72.0"/> + </xsl:when> + <xsl:when test="ends-with($normLength, 'pc')"> + <xsl:value-of select="xs:decimal(substring-before($normLength, 'pc')) * $altova:nPxPerIn div 6.0"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$normLength"/> + </xsl:otherwise> + </xsl:choose> + </xsl:function> + <xsl:function name="altova:convert-length-to-mm" as="xs:decimal"> + <xsl:param name="altova:length"/> + <xsl:variable name="normLength" select="normalize-space($altova:length)"/> + <xsl:choose> + <xsl:when test="ends-with($normLength, 'px')"> + <xsl:value-of select="xs:decimal(substring-before($normLength, 'px')) div $altova:nPxPerIn * 25.4"/> + </xsl:when> + <xsl:when test="ends-with($normLength, 'in')"> + <xsl:value-of select="xs:decimal(substring-before($normLength, 'in')) * 25.4"/> + </xsl:when> + <xsl:when test="ends-with($normLength, 'cm')"> + <xsl:value-of select="xs:decimal(substring-before($normLength, 'cm')) * 10"/> + </xsl:when> + <xsl:when test="ends-with($normLength, 'mm')"> + <xsl:value-of select="substring-before($normLength, 'mm') "/> + </xsl:when> + <xsl:when test="ends-with($normLength, 'pt')"> + <xsl:value-of select="xs:decimal(substring-before($normLength, 'pt')) * 25.4 div 72.0"/> + </xsl:when> + <xsl:when test="ends-with($normLength, 'pc')"> + <xsl:value-of select="xs:decimal(substring-before($normLength, 'pc')) * 25.4 div 6.0"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="number($normLength) div $altova:nPxPerIn * 25.4"/> + </xsl:otherwise> + </xsl:choose> + </xsl:function> +</xsl:stylesheet> diff --git a/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java b/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java new file mode 100644 index 00000000..8d3152b6 --- /dev/null +++ b/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java @@ -0,0 +1,65 @@ +/** ********************************************************************** + * + * Copyright 2019 Jochen Staerk + * + * Use is subject to license terms. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ +package org.mustangproject.ZUGFeRD; + +import junit.framework.Test; +import junit.framework.TestSuite; +import junit.framework.TestCase; + +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +public class BaseTest extends TestCase { + /** + * Create the test case + * + * @param testName name of the test case + */ + public BaseTest(String testName) { + super(testName); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() { + return new TestSuite(BaseTest.class); + } + + public void testCorrectDigits() { + assertEquals("0.00", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal(0),2)); + assertEquals("-1.10", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.10"),2)); + assertEquals("-1.10", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.1"),2)); + assertEquals("-1.01", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.01"),2)); + assertEquals("20000123.35", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3489"),2)); + assertEquals("20000123.34", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3419"),2)); + assertEquals("12.00", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("12"),2)); + assertEquals("12", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("12"),0)); + assertEquals("20000123.342", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3419"),3)); + } + +} diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java index 1aefd3a8..f1d5d001 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java @@ -21,6 +21,7 @@ package org.mustangproject.ZUGFeRD; import java.util.Date; public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTransaction { + private String number; private Date issueDate; private String ownOrganisationFullPlaintextInfo; @@ -30,11 +31,7 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran private IZUGFeRDAllowanceCharge[] zFLogisticsServiceCharges; private IZUGFeRDExportableItem[] zFItems; private IZUGFeRDExportableContact recipient; - private String ownKto; - private String ownBLZ; - private String ownBIC; - private String ownBankName; - private String ownIBAN; + private IZUGFeRDTradeSettlementPayment[] settlementPayments; private String ownTaxID; private String ownVATID; private String ownOrganisationName; @@ -44,7 +41,6 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran private String ownCountry; private Date deliveryDate; private String currency; - private String ownPaymentInfoText; private String paymentTermDescription; private String referenceNumber; @@ -94,28 +90,8 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran } @Override - public String getOwnKto() { - return ownKto; - } - - @Override - public String getOwnBLZ() { - return ownBLZ; - } - - @Override - public String getOwnBIC() { - return ownBIC; - } - - @Override - public String getOwnBankName() { - return ownBankName; - } - - @Override - public String getOwnIBAN() { - return ownIBAN; + public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() { + return settlementPayments; } @Override @@ -163,11 +139,6 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran return currency; } - @Override - public String getOwnPaymentInfoText() { - return ownPaymentInfoText; - } - @Override public String getPaymentTermDescription() { return paymentTermDescription; @@ -223,31 +194,6 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran return this; } - public IZUGFeRDExportableTransactionImpl setOwnBLZ(String ownBLZ) { - this.ownBLZ = ownBLZ; - return this; - } - - public IZUGFeRDExportableTransactionImpl setOwnBIC(String ownBIC) { - this.ownBIC = ownBIC; - return this; - } - - public IZUGFeRDExportableTransactionImpl setOwnBankName(String ownBankName) { - this.ownBankName = ownBankName; - return this; - } - - public IZUGFeRDExportableTransactionImpl setOwnKto(String ownKto) { - this.ownKto = ownKto; - return this; - } - - public IZUGFeRDExportableTransactionImpl setOwnIBAN(String ownIBAN) { - this.ownIBAN = ownIBAN; - return this; - } - public IZUGFeRDExportableTransactionImpl setOwnTaxID(String ownTaxID) { this.ownTaxID = ownTaxID; return this; @@ -293,11 +239,6 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran return this; } - public IZUGFeRDExportableTransactionImpl setOwnPaymentInfoText(String ownPaymentInfoText) { - this.ownPaymentInfoText = ownPaymentInfoText; - return this; - } - public IZUGFeRDExportableTransactionImpl setPaymentTermDescription(String paymentTermDescription) { this.paymentTermDescription = paymentTermDescription; return this; @@ -307,4 +248,9 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran this.referenceNumber = referenceNumber; return this; } + + public IZUGFeRDExportableTransactionImpl setTradeSettlementPayment(IZUGFeRDTradeSettlementPayment... settlementPayments) { + this.settlementPayments = settlementPayments; + return this; + } } diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPaymentImpl.java b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPaymentImpl.java new file mode 100644 index 00000000..8ad9839a --- /dev/null +++ b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDTradeSettlementPaymentImpl.java @@ -0,0 +1,90 @@ +/** ********************************************************************** + * + * Copyright 2019 by ak on 12.04.19. + * + * Use is subject to license terms. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ +package org.mustangproject.ZUGFeRD; + +public class IZUGFeRDTradeSettlementPaymentImpl implements IZUGFeRDTradeSettlementPayment { + + private String ownKto; + private String ownBLZ; + private String ownBIC; + private String ownBankName; + private String ownIBAN; + private String ownPaymentInfoText; + + @Override + public String getOwnKto() { + return ownKto; + } + + @Override + public String getOwnBLZ() { + return ownBLZ; + } + + @Override + public String getOwnBIC() { + return ownBIC; + } + + @Override + public String getOwnBankName() { + return ownBankName; + } + + @Override + public String getOwnIBAN() { + return ownIBAN; + } + + @Override + public String getOwnPaymentInfoText() { + return ownPaymentInfoText; + } + + public IZUGFeRDTradeSettlementPaymentImpl setOwnBLZ(String ownBLZ) { + this.ownBLZ = ownBLZ; + return this; + } + + public IZUGFeRDTradeSettlementPaymentImpl setOwnBIC(String ownBIC) { + this.ownBIC = ownBIC; + return this; + } + + public IZUGFeRDTradeSettlementPaymentImpl setOwnBankName(String ownBankName) { + this.ownBankName = ownBankName; + return this; + } + + public IZUGFeRDTradeSettlementPaymentImpl setOwnKto(String ownKto) { + this.ownKto = ownKto; + return this; + } + + public IZUGFeRDTradeSettlementPaymentImpl setOwnIBAN(String ownIBAN) { + this.ownIBAN = ownIBAN; + return this; + } + + public IZUGFeRDTradeSettlementPaymentImpl setOwnPaymentInfoText(String ownPaymentInfoText) { + this.ownPaymentInfoText = ownPaymentInfoText; + return this; + } + +} diff --git a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderTestCase.java b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderTestCase.java new file mode 100644 index 00000000..9b74f570 --- /dev/null +++ b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderTestCase.java @@ -0,0 +1,226 @@ +/** ********************************************************************** + * + * Copyright 2019 by ak on 12.04.19. + * + * Use is subject to license terms. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ +package org.mustangproject.ZUGFeRD; + +import junit.framework.TestCase; + +import java.math.BigDecimal; + +public abstract class MustangReaderTestCase extends TestCase implements IZUGFeRDExportableTransaction { + + public MustangReaderTestCase(String testName) { + super(testName); + } + + + @Override + public IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() { + Payment[] payments = new Payment[1]; + payments[0] = new Payment(); + return payments; + } + + protected class Payment implements IZUGFeRDTradeSettlementPayment { + + @Override + public String getOwnKto() { + return "44421800"; + } + + @Override + public String getOwnBLZ() { + return "41441604"; + } + + @Override + public String getOwnBIC() { + return "COBADEFFXXX"; + } + + @Override + public String getOwnBankName() { + return "Commerzbank"; + } + + @Override + public String getOwnPaymentInfoText() { + return "Überweisung"; + } + + @Override + public String getOwnIBAN() { + return "DE88 2008 0000 0970 3757 00"; + } + } + + protected class RecipientContact implements IZUGFeRDExportableContact { + + @Override + public String getCountry() { + return "DE"; + } + + @Override + public String getLocation() { + return "Spielkreis"; + } + + @Override + public String getName() { + return "Theodor Est"; + } + + @Override + public String getStreet() { + return "Bahnstr. 42"; + } + + @Override + public String getVATID() { + return "DE999999999"; + } + + @Override + public String getZIP() { + return "88802"; + } + } + + protected class SenderContact implements IZUGFeRDExportableContact { + + + + @Override + public String getName() { + return "Ingmar N. Fo"; + } + + @Override + public String getPhone() { + return "++49(0)237823"; + } + + @Override + public String getEMail() { + return "info@localhost.local"; + } + + } + + protected class Item implements IZUGFeRDExportableItem { + + public Item(BigDecimal price, BigDecimal quantity, Product product) { + super(); + this.price = price; + this.quantity = quantity; + this.product = product; + } + + private BigDecimal price, quantity; + private Product product; + + @Override + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + @Override + public BigDecimal getQuantity() { + return quantity; + } + + public void setQuantity(BigDecimal quantity) { + this.quantity = quantity; + } + + @Override + public Product getProduct() { + return product; + } + + public void setProduct(Product product) { + this.product = product; + } + + @Override + public IZUGFeRDAllowanceCharge[] getItemAllowances() { + return null; + } + + @Override + public IZUGFeRDAllowanceCharge[] getItemCharges() { + return null; + } + + } + + protected class Product implements IZUGFeRDExportableProduct { + private String description, name, unit; + private BigDecimal VATPercent; + + public Product(String description, String name, String unit, BigDecimal VATPercent) { + super(); + this.description = description; + this.name = name; + this.unit = unit; + this.VATPercent = VATPercent; + } + + @Override + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String getUnit() { + return unit; + } + + public void setUnit(String unit) { + this.unit = unit; + } + + @Override + public BigDecimal getVATPercent() { + return VATPercent; + } + + public void setVATPercent(BigDecimal VATPercent) { + this.VATPercent = VATPercent; + } + } + +} diff --git a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java index 07b03609..e1908c7b 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java @@ -27,6 +27,7 @@ import org.junit.runners.MethodSorters; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class MustangReaderWriterCustomXMLTest extends TestCase { @@ -49,7 +50,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { // //////// TESTS // ////////////////////////////////////////////////////////////////////////////////////////// - public void testCustomZF2Export() throws Exception { + public void testCustomZF2Export() { final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506custom.pdf"; // the writing part @@ -61,8 +62,10 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { .load(SOURCE_PDF); final byte[] UTF8ByteOrderMark = new byte[]{(byte) 0xef, (byte) 0xbb, (byte) 0xbf}; - /* we have much more information than just in the basic profile (comfort or extended) but it's perfectly valid to provide more information, just not less. */ - String ownZUGFeRDXML = new String(UTF8ByteOrderMark) + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + + /* we have much more information than just in the basic profile (comfort or extended) but it's perfectly valid to provide more information, just not less. + * test the export with bom (which is valid) because this will also test the import (which also needs to work and needs to be tested) + * */ + String ownZUGFeRDXML = new String(UTF8ByteOrderMark, StandardCharsets.UTF_8) + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<rsm:CrossIndustryInvoice xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:rsm=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100\" xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100\" xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100\">\n" + " <rsm:ExchangedDocumentContext>\n" + " <ram:TestIndicator><udt:Indicator>false</udt:Indicator></ram:TestIndicator>\n" + @@ -286,10 +289,10 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { * ./src/test/MustangGnuaccountingBeispielRE-20140703_502blanko.pdf}, adds * metadata, writes to @{code ./target/testout-*} and then imports to check the * values. It would not make sense to have it run before the less complex - * importer test (which is probably redundant) --> as only Name Ascending is + * importer test (which is probably redundant). As only Name Ascending is * supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export */ - public void testCustomZF1Export() throws Exception { + public void testCustomZF1Export() { final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20170509_505custom.pdf"; // the writing part @@ -297,7 +300,10 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { try { InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf"); - ZUGFeRDExporter zea1 = new ZUGFeRDExporterFromA1Factory().setProducer("My Application").setCreator("Test").setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.BASIC) + ZUGFeRDExporter zea1 = new ZUGFeRDExporterFromA1Factory() + .setProducer("My Application") + .setCreator("Test") + .setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.BASIC) .load(SOURCE_PDF); /* we have much more information than just in the basic profile (comfort or extended) but it's perfectly valid to provide more information, just not less. */ String ownZUGFeRDXML = "<rsm:CrossIndustryDocument xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12\" xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15\" xmlns:rsm=\"urn:ferd:CrossIndustryDocument:invoice:1p0\">\n" diff --git a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java index 84fd2fa3..a104fccf 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java @@ -19,7 +19,6 @@ package org.mustangproject.ZUGFeRD; import junit.framework.Test; -import junit.framework.TestCase; import junit.framework.TestSuite; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; @@ -33,7 +32,7 @@ import java.util.Date; import java.util.GregorianCalendar; @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExportableTransaction { +public class MustangReaderWriterEdgeTest extends MustangReaderTestCase { @Override public Date getDeliveryDate() { @@ -55,36 +54,11 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp return "RE-20170509/505"; } - @Override - public String getOwnKto() { - return "44421800"; - } - - @Override - public String getOwnBLZ() { - return "41441604"; - } - - @Override - public String getOwnBIC() { - return "COBADEFFXXX"; - } - - @Override - public String getOwnBankName() { - return "Commerzbank"; - } - @Override public String getOwnCountry() { return "DE"; } - @Override - public String getOwnIBAN() { - return "DE88 2008 0000 0970 3757 00"; - } - @Override public String getOwnLocation() { return "Stadthausen"; @@ -100,6 +74,13 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp return "Ecke 12"; } + + @Override + public IZUGFeRDExportableContact getOwnContact() { + return new SenderContact(); + + } + @Override public String getOwnTaxID() { return "22/815/0815/4"; @@ -117,10 +98,9 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp @Override public IZUGFeRDExportableContact getRecipient() { - return new Contact(); + return new RecipientContact(); } - @Override public String getOwnOrganisationFullPlaintextInfo() { return null; @@ -144,11 +124,6 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp return allItems; } - @Override - public String getOwnPaymentInfoText() { - return "Überweisung"; - } - @Override public String getPaymentTermDescription() { SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); @@ -172,141 +147,7 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp @Override public String getReferenceNumber() { - return null; - } - - class Contact implements IZUGFeRDExportableContact { - - @Override - public String getCountry() { - return "DE"; - } - - @Override - public String getLocation() { - return "Spielkreis"; - } - - @Override - public String getName() { - return "Theodor Est"; - } - - @Override - public String getStreet() { - return "Bahnstr. 42"; - } - - @Override - public String getVATID() { - return "DE999999999"; - } - - @Override - public String getZIP() { - return "88802"; - } - } - - class Item implements IZUGFeRDExportableItem { - - public Item(BigDecimal price, BigDecimal quantity, Product product) { - super(); - this.price = price; - this.quantity = quantity; - this.product = product; - } - - private BigDecimal price, quantity; - private Product product; - - @Override - public BigDecimal getPrice() { - return price; - } - - public void setPrice(BigDecimal price) { - this.price = price; - } - - @Override - public BigDecimal getQuantity() { - return quantity; - } - - public void setQuantity(BigDecimal quantity) { - this.quantity = quantity; - } - - @Override - public Product getProduct() { - return product; - } - - public void setProduct(Product product) { - this.product = product; - } - - @Override - public IZUGFeRDAllowanceCharge[] getItemAllowances() { - return null; - } - - @Override - public IZUGFeRDAllowanceCharge[] getItemCharges() { - return null; - } - - } - - class Product implements IZUGFeRDExportableProduct { - private String description, name, unit; - private BigDecimal VATPercent; - - public Product(String description, String name, String unit, BigDecimal VATPercent) { - super(); - this.description = description; - this.name = name; - this.unit = unit; - this.VATPercent = VATPercent; - } - - @Override - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String getUnit() { - return unit; - } - - public void setUnit(String unit) { - this.unit = unit; - } - - @Override - public BigDecimal getVATPercent() { - return VATPercent; - } - - public void setVATPercent(BigDecimal vATPercent) { - VATPercent = vATPercent; - } - + return "AB321"; } /** @@ -329,22 +170,20 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp /** * The importer test imports from ./src/test/MustangGnuaccountingBeispielRE-20170509_505.pdf to check the values. - * --> as only Name Ascending is supported for Test Unit sequence, I renamed the this test-A-Export to run before + * As only Name Ascending is supported for Test Unit sequence, I renamed the this test-A-Import to run before * testZExport - * - * @throws IOException */ - public void testAImport() throws IOException { + public void testAImport() { InputStream inputStream = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505.pdf"); ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream); // Reading ZUGFeRD assertEquals(zi.getAmount(), "571.04"); - assertEquals(zi.getBIC(), getOwnBIC()); - assertEquals(zi.getBLZ(), getOwnBLZ()); - assertEquals(zi.getIBAN(), getOwnIBAN()); - assertEquals(zi.getKTO(), getOwnKto()); + assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); + assertEquals(zi.getBLZ(), getTradeSettlementPayment()[0].getOwnBLZ()); + assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); + assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto()); assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getDueDate(), "20170530"); assertEquals(zi.getForeignReference(), getNumber()); @@ -354,12 +193,11 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp /** * The exporter test bases on @{code ./src/test/MustangGnuaccountingBeispielRE-20140703_502blanko.pdf}, adds metadata, - * writes - * to @{code ./target/testout-*} and then imports to check the values. - * It would not make sense to have it run before the less complex importer test (which is probably redundant) - * --> as only Name Ascending is supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export + * writes to @{code ./target/testout-*} and then imports to check the values. + * It would not make sense to have it run before the less complex importer test (which is probably redundant). + * As only Name Ascending is supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export */ - public void testEdgeExport() throws Exception { + public void testEdgeExport() { final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20170509_505newEdge.pdf"; // the writing part @@ -370,13 +208,15 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory() .setProducer("My Application") .setCreator(System.getProperty("user.name")) + .setZUGFeRDVersion(1) .ignorePDFAErrors() .load(SOURCE_PDF)) { - ze.setZUGFeRDVersion(1); ze.PDFattachZugferdFile(this); String theXML = new String(ze.getProvider().getXML()); assertTrue(theXML.contains("<rsm:CrossIndustryDocument")); ze.export(TARGET_PDF); + } catch (IOException e) { + fail("IOException should not happen in testEdgeExport"); } // now check the contents (like MustangReaderTest) @@ -384,10 +224,10 @@ public class MustangReaderWriterEdgeTest extends TestCase implements IZUGFeRDExp // Reading ZUGFeRD assertEquals(zi.getAmount(), "571.04"); - assertEquals(zi.getBIC(), getOwnBIC()); - assertEquals(zi.getBLZ(), getOwnBLZ()); - assertEquals(zi.getIBAN(), getOwnIBAN()); - assertEquals(zi.getKTO(), getOwnKto()); + assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); + assertEquals(zi.getBLZ(), getTradeSettlementPayment()[0].getOwnBLZ()); + assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); + assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto()); assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getForeignReference(), getNumber()); } diff --git a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java index a041a7e8..38f9a552 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java @@ -19,62 +19,49 @@ package org.mustangproject.ZUGFeRD; import junit.framework.Test; -import junit.framework.TestCase; import junit.framework.TestSuite; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.common.PDMetadata; +import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException; +import org.apache.xmpbox.XMPMetadata; +import org.apache.xmpbox.schema.PDFAIdentificationSchema; +import org.apache.xmpbox.xml.DomXmpParser; +import org.apache.xmpbox.xml.XmpParsingException; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +import org.mustangproject.ZUGFeRD.model.DocumentContextParameterTypeConstants; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; +import java.util.*; @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExportableTransaction { +public class MustangReaderWriterTest extends MustangReaderTestCase { @Override public Date getDeliveryDate() { - return new GregorianCalendar(2017, Calendar.NOVEMBER, 17).getTime(); + return new GregorianCalendar(2019, Calendar.JUNE, 10).getTime(); } @Override public Date getDueDate() { - return new GregorianCalendar(2017, Calendar.DECEMBER, 9).getTime(); + return new GregorianCalendar(2019, Calendar.JULY, 1).getTime(); } @Override public Date getIssueDate() { - return new GregorianCalendar(2017, Calendar.NOVEMBER, 18).getTime(); + return new GregorianCalendar(2019, Calendar.JUNE, 10).getTime(); } @Override public String getNumber() { - return "RE-20171118/506"; - } - - @Override - public String getOwnKto() { - return "44421800"; - } - - @Override - public String getOwnBLZ() { - return "41441604"; - } - - @Override - public String getOwnBIC() { - return "COBADEFFXXX"; - } - - @Override - public String getOwnBankName() { - return "Commerzbank"; + return "RE-20190610/507"; } @Override @@ -82,11 +69,6 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta return "DE"; } - @Override - public String getOwnIBAN() { - return "DE88 2008 0000 0970 3757 00"; - } - @Override public String getOwnLocation() { return "Stadthausen"; @@ -119,7 +101,12 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta @Override public IZUGFeRDExportableContact getRecipient() { - return new Contact(); + return new RecipientContact(); + } + + @Override + public IZUGFeRDExportableContact getOwnContact() { + return new SenderContact(); } @Override @@ -135,26 +122,21 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta @Override public IZUGFeRDExportableItem[] getZFItems() { Item[] allItems = new Item[3]; - Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR", + Product designProduct = new Product("", "Design (hours): Of a sample invoice", "HUR", new BigDecimal("7.000000")); - Product balloonProduct = new Product("", "Luftballon: Bunt, ca. 500ml", "C62", new BigDecimal("19.000000")); - Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000")); + Product balloonProduct = new Product("", "Ballons: various colors, ~2000ml", "C62", new BigDecimal("19.000000")); + Product airProduct = new Product("", "Hot air „heiße Luft“ (litres)", "LTR", new BigDecimal("19.000000")); allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct); allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct); - allItems[2] = new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct); + allItems[2] = new Item(new BigDecimal("0.025"), new BigDecimal("800"), airProduct); return allItems; } - @Override - public String getOwnPaymentInfoText() { - return "Überweisung"; - } - @Override public String getPaymentTermDescription() { - SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); - return "Zahlbar ohne Abzug bis zum " + germanDateFormat.format(getDueDate()); + SimpleDateFormat isoDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + return "Remit until " + isoDateFormat.format(getDueDate()); } @Override @@ -180,141 +162,7 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta @Override public String getReferenceNumber() { - return null; - } - - class Contact implements IZUGFeRDExportableContact { - - @Override - public String getCountry() { - return "DE"; - } - - @Override - public String getLocation() { - return "Spielkreis"; - } - - @Override - public String getName() { - return "Theodor Est"; - } - - @Override - public String getStreet() { - return "Bahnstr. 42"; - } - - @Override - public String getVATID() { - return "DE999999999"; - } - - @Override - public String getZIP() { - return "88802"; - } - } - - class Item implements IZUGFeRDExportableItem { - - public Item(BigDecimal price, BigDecimal quantity, Product product) { - super(); - this.price = price; - this.quantity = quantity; - this.product = product; - } - - private BigDecimal price, quantity; - private Product product; - - @Override - public BigDecimal getPrice() { - return price; - } - - public void setPrice(BigDecimal price) { - this.price = price; - } - - @Override - public BigDecimal getQuantity() { - return quantity; - } - - public void setQuantity(BigDecimal quantity) { - this.quantity = quantity; - } - - @Override - public Product getProduct() { - return product; - } - - public void setProduct(Product product) { - this.product = product; - } - - @Override - public IZUGFeRDAllowanceCharge[] getItemAllowances() { - return null; - } - - @Override - public IZUGFeRDAllowanceCharge[] getItemCharges() { - return null; - } - - } - - class Product implements IZUGFeRDExportableProduct { - private String description, name, unit; - private BigDecimal VATPercent; - - public Product(String description, String name, String unit, BigDecimal VATPercent) { - super(); - this.description = description; - this.name = name; - this.unit = unit; - this.VATPercent = VATPercent; - } - - @Override - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String getUnit() { - return unit; - } - - public void setUnit(String unit) { - this.unit = unit; - } - - @Override - public BigDecimal getVATPercent() { - return VATPercent; - } - - public void setVATPercent(BigDecimal VATPercent) { - this.VATPercent = VATPercent; - } - + return "AB321"; } /** @@ -337,29 +185,27 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta // ////////////////////////////////////////////////////////////////////////////////////////// /** - * The importer test imports from - * ./src/test/MustangGnuaccountingBeispielRE-20170509_505.pdf to check the - * values. --> as only Name Ascending is supported for Test Unit sequence, I - * renamed the this test-A-Export to run before testZExport - * - * @throws IOException + * The importer test imports from ./src/test/MustangGnuaccountingBeispielRE-20170509_505.pdf to check the + * values. As only Name Ascending is supported for Test Unit sequence, I renamed the this testAImport + * to run before testZExport */ - public void testAImport() throws IOException { + public void testAImport() { InputStream inputStream = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505.pdf"); ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream); // Reading ZUGFeRD assertEquals(zi.getAmount(), "571.04"); - assertEquals(zi.getBLZ(), getOwnBLZ()); - assertEquals(zi.getBIC(), getOwnBIC()); - assertEquals(zi.getIBAN(), getOwnIBAN()); - assertEquals(zi.getKTO(), getOwnKto()); + assertEquals(zi.getBLZ(), getTradeSettlementPayment()[0].getOwnBLZ()); + assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); + assertEquals(zi.getIBAN(),getTradeSettlementPayment()[0].getOwnIBAN()); + assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto()); assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getForeignReference(), "RE-20170509/505"); + assertEquals(zi.getBankName(), "Commerzbank"); } - public void testForeignImport() throws IOException { + public void testForeignImport() { InputStream inputStream = this.getClass().getResourceAsStream("/zugferd_invoice.pdf"); ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream); @@ -456,8 +302,39 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setAttachZUGFeRDHeaders(false).load(SOURCE_PDF); File tempFile = File.createTempFile("ZUGFeRD-", "-test"); - ze.export(tempFile.getName()); + ze.export(tempFile.getAbsolutePath()); tempFile.deleteOnExit(); + checkPdfA3B(tempFile); + } + + public void testMigratePDFA1ToA3Stream() throws IOException { + // just make sure there is no Exception + InputStream SOURCE_PDF = this.getClass() + .getResourceAsStream("/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf"); + + ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setAttachZUGFeRDHeaders(false).load(SOURCE_PDF); + + File tempFile = File.createTempFile("ZUGFeRD-", "-test"); + tempFile.deleteOnExit(); + try (FileOutputStream fos = new FileOutputStream(tempFile)) { + ze.export(fos); + } + checkPdfA3B(tempFile); + } + + private void checkPdfA3B(File tempFile) throws IOException, InvalidPasswordException { + try (PDDocument doc = PDDocument.load(tempFile)) { + PDMetadata metadata = doc.getDocumentCatalog().getMetadata(); + InputStream exportXMPMetadata = metadata.exportXMPMetadata(); + byte[] xmpBytes = new byte[exportXMPMetadata.available()]; + exportXMPMetadata.read(xmpBytes); + final XMPMetadata xmp = new DomXmpParser().parse(xmpBytes); + PDFAIdentificationSchema pdfaid = xmp.getPDFIdentificationSchema(); + assertEquals(pdfaid.getPart().intValue(), 3); + assertEquals(pdfaid.getConformance(), "U"); + } catch (XmpParsingException e) { + throw new IllegalStateException("Failed to read PDF", e); + } } /** @@ -465,16 +342,16 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta * ./src/test/MustangGnuaccountingBeispielRE-20140703_502blanko.pdf}, adds * metadata, writes to @{code ./target/testout-*} and then imports to check the * values. It would not make sense to have it run before the less complex - * importer test (which is probably redundant) --> as only Name Ascending is + * importer test (which is probably redundant). As only Name Ascending is * supported for Test Unit sequence, I renamed the Exporter Test test-Z-Export */ - public void testZExport() throws Exception { + public void testZExport() { final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506new.pdf"; // the writing part try (InputStream SOURCE_PDF = this.getClass() - .getResourceAsStream("/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf"); + .getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf"); ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) { @@ -488,10 +365,12 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta String pdfContent = baos.toString("UTF-8"); assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1); // check for pdf-a schema extension - assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1); - assertFalse(pdfContent.indexOf("<pdfaSchema:prefix>zf</pdfaSchema:prefix>") == -1); - assertFalse(pdfContent.indexOf("urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#") == -1); - +// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1); +// assertFalse(pdfContent.indexOf("<pdfaSchema:prefix>zf</pdfaSchema:prefix>") == -1); +// assertFalse(pdfContent.indexOf("urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#") == -1); + + } catch (IOException e) { + fail("IOException should not happen in testZExport"); } // now check the contents (like MustangReaderTest) @@ -499,14 +378,46 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta // Reading ZUGFeRD assertEquals(zi.getAmount(), "571.04"); - assertEquals(zi.getBIC(), getOwnBIC()); - assertEquals(zi.getIBAN(), getOwnIBAN()); - assertEquals(zi.getKTO(), getOwnKto()); + assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); + assertEquals(zi.getReference(), getReferenceNumber()); + assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); + assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto()); assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getForeignReference(), getNumber()); } - /* + /** + * Quick and dirty copy of testZExport to check if v1 files contain + * the correct profile string when the comfort profile is selected. + */ + public void testZExportv1Profile() { + + final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506new.pdf"; + + // the writing part + try (InputStream SOURCE_PDF = this.getClass() + .getResourceAsStream("/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf"); + + ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(1).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.COMFORT).load(SOURCE_PDF)) { + + ze.PDFattachZugferdFile(this); + ze.disableAutoClose(true); + ze.export(TARGET_PDF); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ze.export(baos); + ze.close(); + String pdfContent = baos.toString("UTF-8"); + assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.BASIC) >= 0); + assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.EXTENDED) >= 0); + assertTrue(pdfContent.indexOf(DocumentContextParameterTypeConstants.COMFORT) >= 0); + + } catch (IOException e) { + fail("IOException should not happen in testZExport"); + } + } + + public void testFXExport() throws Exception { final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506fx.pdf"; @@ -515,7 +426,7 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta try (InputStream SOURCE_PDF = this.getClass() .getResourceAsStream("/MustangGnuaccountingBeispielRE-20171118_506blanko.pdf"); - ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) { + ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setZUGFeRDVersion(2).setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel.EN16931).load(SOURCE_PDF)) { ze.setFacturX(); ze.PDFattachZugferdFile(this); ze.disableAutoClose(true); @@ -529,7 +440,7 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta // check for pdf-a schema extension assertFalse(pdfContent.indexOf("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>") == -1); assertFalse(pdfContent.indexOf("<pdfaSchema:prefix>fx</pdfaSchema:prefix>") == -1); - assertFalse(pdfContent.indexOf("urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931") == -1); + assertFalse(pdfContent.indexOf("urn:cen.eu:en16931:2017") == -1); } // now check the contents (like MustangReaderTest) @@ -537,18 +448,14 @@ public class MustangReaderWriterTest extends TestCase implements IZUGFeRDExporta // Reading ZUGFeRD assertEquals(zi.getAmount(), "571.04"); - assertEquals(zi.getBIC(), getOwnBIC()); - assertEquals(zi.getIBAN(), getOwnIBAN()); - assertEquals(zi.getKTO(), getOwnKto()); + assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); + assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); + assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto()); assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getForeignReference(), getNumber()); } -*/ - /** - * @throws Exception - * @Test(expected = IndexOutOfBoundsException.class) - */ - public void testExceptionOnPDF14() throws Exception { + + public void testExceptionOnPDF14() { final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20170509_505new.pdf"; diff --git a/src/test/java/org/mustangproject/ZUGFeRD/ResourceUtilities.java b/src/test/java/org/mustangproject/ZUGFeRD/ResourceUtilities.java index 2a36e4ef..cf908e72 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/ResourceUtilities.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/ResourceUtilities.java @@ -34,6 +34,10 @@ public class ResourceUtilities { /** * Loading a File into a String using a certain encoding and file path + * @param encoding the charset used in the file + * @param path the path to the file + * @return the file contents as a String + * @throws IOException if the file cannot be read */ public static String readFile(Charset encoding, String path) throws IOException { byte[] content = Files.readAllBytes(Paths.get(path)); @@ -42,6 +46,10 @@ public class ResourceUtilities { /** * Saving a String as a file to a certain file path + * @param encoding the charset used in the file + * @param path the path to the file + * @param content the contents of the file + * @throws FileNotFoundException if the file cannot be found */ public static void saveFile(Charset encoding, String path, String content) throws FileNotFoundException { @@ -147,7 +155,7 @@ public class ResourceUtilities { /** * To fix the 3 slashes bug for File URI: For example: - * file:/C:/work/test.txt -> file:///C:/work/test.txt + * file:/C:/work/test.txt gives file:///C:/work/test.txt * * @param u - the File URI * @return the String of the URI diff --git a/src/test/java/org/mustangproject/ZUGFeRD/VersionMigrationTest.java b/src/test/java/org/mustangproject/ZUGFeRD/VersionMigrationTest.java index ab628dcd..62e83b67 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/VersionMigrationTest.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/VersionMigrationTest.java @@ -41,7 +41,7 @@ import static org.junit.Assert.assertFalse; * will be migrated to <code>src/test/resources/migration/output</code>. * If there is a similar named file as test reference <code>src/test/resources/migration/reference</code> a test * will be triggered for every single file. - * <p/> + * * Note: Any 'ZUGFeRD1' will be exchanged to 'ZUGFeRD2' during migration and adequate reference will be searched for. */ @RunWith(Parameterized.class) diff --git a/src/test/java/org/mustangproject/ZUGFeRD/ZF2EdgeTest.java b/src/test/java/org/mustangproject/ZUGFeRD/ZF2EdgeTest.java new file mode 100644 index 00000000..a4f4dc13 --- /dev/null +++ b/src/test/java/org/mustangproject/ZUGFeRD/ZF2EdgeTest.java @@ -0,0 +1,209 @@ +/** ********************************************************************** + * + * Copyright 2019 Jochen Staerk + * + * Use is subject to license terms. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ +package org.mustangproject.ZUGFeRD; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class ZF2EdgeTest extends MustangReaderTestCase { + final String TARGET_PDF = "./target/testout-ZF2newEdge.pdf"; + + @Override + public Date getDeliveryDate() { + return new GregorianCalendar(2017, Calendar.MAY, 7).getTime(); + } + + @Override + public Date getDueDate() { + return new GregorianCalendar(2017, Calendar.MAY, 30).getTime(); + } + + @Override + public Date getIssueDate() { + return new GregorianCalendar(2017, Calendar.MAY, 9).getTime(); + } + + @Override + public String getNumber() { + return "RE-20170509/505"; + } + + @Override + public String getOwnCountry() { + return "DE"; + } + + @Override + public String getOwnLocation() { + return "Stadthausen"; + } + + @Override + public String getOwnOrganisationName() { + return "Bei Spiel GmbH"; + } + + @Override + public String getOwnStreet() { + return "Ecke 12"; + } + + + @Override + public IZUGFeRDExportableContact getOwnContact() { + return new SenderContact(); + + } + + @Override + public String getOwnTaxID() { + return "22/815/0815/4"; + } + + @Override + public String getOwnVATID() { + return "DE136695976"; + } + + @Override + public String getOwnZIP() { + return "12345"; + } + + @Override + public IZUGFeRDExportableContact getRecipient() { + return new RecipientContact(); + } + + @Override + public String getOwnOrganisationFullPlaintextInfo() { + return null; + } + + @Override + public String getCurrency() { + return "EUR"; + } + + @Override + public IZUGFeRDExportableItem[] getZFItems() { + Item[] allItems = new Item[3]; + Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR", new BigDecimal("7.000000")); + Product balloonProduct = new Product("", "Bestellerweiterung für E&F Umbau", "C62", new BigDecimal("19.000000"));// test for issue 103 + Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000")); + + allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct); + allItems[1] = new Item(new BigDecimal("0.79"), new BigDecimal("400"), balloonProduct); + allItems[2] = new Item(new BigDecimal("0.10"), new BigDecimal("200"), airProduct); + return allItems; + } + + @Override + public String getPaymentTermDescription() { + SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); + return "Zahlbar ohne Abzug bis zum " + germanDateFormat.format(getDueDate()); + } + + @Override + public IZUGFeRDAllowanceCharge[] getZFAllowances() { + return null; + } + + @Override + public IZUGFeRDAllowanceCharge[] getZFCharges() { + return null; + } + + @Override + public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() { + return null; + } + + @Override + public String getReferenceNumber() { + return "AB321"; + } + + /** + * Create the test case + * + * @param testName name of the test case + */ + public ZF2EdgeTest(String testName) { + super(testName); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() { + return new TestSuite(ZF2EdgeTest.class); + } + + + // //////// TESTS ////////////////////////////////////////////////////////////////////////////////////////// + + /** + * The exporter test bases on @{code ./src/test/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf}, adds metadata, + * writes to @{code ./target/testout-*} and then imports to check the values. + */ + public void testEdgeExport() { + + // the writing part + + try (InputStream SOURCE_PDF = + this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf"); + + ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory() + .setProducer("My Application") + .setCreator(System.getProperty("user.name")) + .setZUGFeRDVersion(2) + .ignorePDFAErrors() + .load(SOURCE_PDF)) { + ze.PDFattachZugferdFile(this); + String theXML = new String(ze.getProvider().getXML()); + assertTrue(theXML.contains("<rsm:CrossIndustryInvoice")); + ze.export(TARGET_PDF); + } catch (IOException e) { + fail("IOException should not be raised in testEdgeExport"); + } + + // now check the contents (like MustangReaderTest) + ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF); + + // Reading ZUGFeRD + assertEquals(zi.getAmount(), "571.04"); + assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); + assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); + assertEquals(zi.getHolder(), getOwnOrganisationName()); + assertEquals(zi.getForeignReference(), getNumber()); + } + +} diff --git a/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java b/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java index 2e284fdd..5497d282 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java @@ -45,7 +45,7 @@ public class ZUGFeRDTransactionModelConverterTest { .setOwnStreet("own street") .setOwnCountry("own country") .setOwnLocation("own city") - .setOwnBankName("own bank") + .setTradeSettlementPayment(new IZUGFeRDTradeSettlementPaymentImpl().setOwnBankName("own bank")) .setZFItems( new IZUGFeRDExportableItemImpl() .setProduct(new IZUGFeRDExportableProductImpl() diff --git a/src/test/resources/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf b/src/test/resources/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf new file mode 100644 index 00000000..9c4ae558 Binary files /dev/null and b/src/test/resources/MustangGnuaccountingBeispielRE-20190610_507blanko.pdf differ diff --git a/src/test/resources/migration/input/ZUGFeRD1_COMFORT_Einfach.xml b/src/test/resources/migration/input/ZUGFeRD1_COMFORT_Einfach.xml new file mode 100644 index 00000000..db6672dd --- /dev/null +++ b/src/test/resources/migration/input/ZUGFeRD1_COMFORT_Einfach.xml @@ -0,0 +1,216 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + +Nutzungsrechte +ZUGFeRD Datenformat Version 1.0, 25.6.2014 +Beispiel Version 29.09.2014 + +Zweck des Forums für elektronische Rechnungen bei der AWV e.V („FeRD“) ist u.a. die Schaffung und Spezifizierung +eines offenen Datenformats für strukturierten elektronischen Datenaustausch auf der Grundlage offener und nicht +diskriminierender, standardisierter Technologien („ZUGFeRD Datenformat“) + +Das ZUGFeRD Datenformat wird nach Maßgabe des FeRD sowohl Unternehmen als auch der öffentlichen Verwaltung +frei zugänglich gemacht. Hierfür bietet FeRD allen Unternehmen und Organisationen der öffentlichen Verwaltung eine +Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD-Datenformats zu fairen, sachgerechten und nicht +diskriminierenden Bedingungen an. + +Die Spezifikation des FeRD zur Implementierung des ZUGFeRD Datenformats ist in ihrer jeweils geltenden Fassung +abrufbar unter www.ferd-net.de. + +Im Einzelnen schließt die Nutzungsgewährung ein: +===================================== + +FeRD räumt eine Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD Datenformats in der jeweils +geltenden und akzeptierten Fassung (www.ferd-net.de) ein. +Die Lizenz beinhaltet ein unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, +Weiterbearbeitung und Verbindung mit anderen Produkten. +Die Lizenz gilt insbesondere für die Entwicklung, die Gestaltung, die Herstellung, den Verkauf, die Nutzung oder +anderweitige Verwendung des ZUGFeRD Datenformats für Hardware- und/oder Softwareprodukte sowie sonstige +Anwendungen und Dienste. +Diese Lizenz schließt nicht die wesentlichen Patente der Mitglieder von FeRD ein. Als wesentliche Patente sind Patente +und Patentanmeldungen weltweit zu verstehen, die einen oder mehrere Patentansprüche beinhalten, bei denen es sich um +notwendige Ansprüche handelt. Notwendige Ansprüche sind lediglich jene Ansprüche der Wesentlichen Patente, die durch +die Implementierung des ZUGFeRD Datenformats notwendigerweise verletzt würden. +Der Lizenznehmer ist berechtigt, seinen jeweiligen Konzerngesellschaften ein unbefristetes, weltweites, nicht übertragbares, +unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, Weiterbearbeitung und Verbindung mit +anderen Produkten einzuräumen. + +Die Lizenz wird kostenfrei zur Verfügung gestellt. + +Außer im Falle vorsätzlichen Verschuldens oder grober Fahrlässigkeit haftet FeRD weder für Nutzungsausfall, entgangenen +Gewinn, Datenverlust, Kommunikationsverlust, Einnahmeausfall, Vertragseinbußen, Geschäftsausfall oder für Kosten, +Schäden, Verluste oder Haftpflichten im Zusammenhang mit einer Unterbrechung der Geschäftstätigkeit, noch für konkrete, +beiläufig entstandene, mittelbare Schäden, Straf- oder Folgeschäden und zwar auch dann nicht, wenn die Möglichkeit der +Kosten, Verluste bzw. Schäden hätte normalerweise vorhergesehen werden können. + +--> +<rsm:CrossIndustryDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rsm="urn:ferd:CrossIndustryDocument:invoice:1p0" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15"> + <rsm:SpecifiedExchangedDocumentContext> + <ram:TestIndicator><udt:Indicator>true</udt:Indicator></ram:TestIndicator><!-- Im Echtbetrieb muss der TestIndicator entweder vollständig entfallen oder auf false stehen. --> + <ram:GuidelineSpecifiedDocumentContextParameter> + <ram:ID>urn:ferd:CrossIndustryDocument:invoice:1p0:comfort</ram:ID> + </ram:GuidelineSpecifiedDocumentContextParameter> + </rsm:SpecifiedExchangedDocumentContext> + <rsm:HeaderExchangedDocument> + <ram:ID>471102</ram:ID> + <ram:Name>RECHNUNG</ram:Name> + <ram:TypeCode>380</ram:TypeCode> + <ram:IssueDateTime><udt:DateTimeString format="102">20130305</udt:DateTimeString></ram:IssueDateTime> + <ram:IncludedNote> + <ram:Content>Rechnung gemäß Bestellung vom 01.03.2013.</ram:Content> + </ram:IncludedNote> + <ram:IncludedNote> + <ram:Content>Lieferant GmbH +Lieferantenstraße 20 +80333 München +Deutschland +Geschäftsführer: Hans Muster +Handelsregisternummer: H A 123 +</ram:Content> +<ram:SubjectCode>REG</ram:SubjectCode> + </ram:IncludedNote> + </rsm:HeaderExchangedDocument> + <rsm:SpecifiedSupplyChainTradeTransaction> + <ram:ApplicableSupplyChainTradeAgreement> + <ram:SellerTradeParty> + <ram:GlobalID schemeID="0088">4000001123452</ram:GlobalID> + <ram:Name>Lieferant GmbH</ram:Name> + <ram:PostalTradeAddress> + <ram:PostcodeCode>80333</ram:PostcodeCode> + <ram:LineOne>Lieferantenstraße 20</ram:LineOne> + <ram:CityName>München</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="FC">201/113/40209</ram:ID> + </ram:SpecifiedTaxRegistration> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">DE123456789</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:SellerTradeParty> + <ram:BuyerTradeParty> + <ram:ID>GE2020211</ram:ID> + <ram:GlobalID schemeID="0088">4000001987658</ram:GlobalID> + <ram:Name>Kunden AG Mitte</ram:Name> + <ram:DefinedTradeContact> + <ram:PersonName>Hans Muster</ram:PersonName> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>69876</ram:PostcodeCode> + <ram:LineOne>Kundenstraße 15</ram:LineOne> + <ram:CityName>Frankfurt</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + </ram:BuyerTradeParty> + </ram:ApplicableSupplyChainTradeAgreement> + <ram:ApplicableSupplyChainTradeDelivery> + <ram:ActualDeliverySupplyChainEvent> + <ram:OccurrenceDateTime><udt:DateTimeString format="102">20130305</udt:DateTimeString> </ram:OccurrenceDateTime> + </ram:ActualDeliverySupplyChainEvent> + </ram:ApplicableSupplyChainTradeDelivery> + <ram:ApplicableSupplyChainTradeSettlement> + <ram:PaymentReference>2013-471102</ram:PaymentReference> + <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode> + <ram:SpecifiedTradeSettlementPaymentMeans> + <ram:TypeCode>31</ram:TypeCode> + <ram:Information>Überweisung</ram:Information> + <ram:PayeePartyCreditorFinancialAccount> + <ram:IBANID>DE08700901001234567890</ram:IBANID> + </ram:PayeePartyCreditorFinancialAccount> + <ram:PayeeSpecifiedCreditorFinancialInstitution> + <ram:BICID>GENODEF1M04</ram:BICID> + </ram:PayeeSpecifiedCreditorFinancialInstitution> + </ram:SpecifiedTradeSettlementPaymentMeans> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount currencyID="EUR">19.25</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount currencyID="EUR">275.00</ram:BasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>7.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount currencyID="EUR">37.62</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount currencyID="EUR">198.00</ram:BasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>19.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradePaymentTerms> + <ram:Description>Zahlbar innerhalb 30 Tagen netto bis 04.04.2013, 3% Skonto innerhalb 10 Tagen bis 15.03.2013</ram:Description> + <ram:DueDateDateTime><udt:DateTimeString format="102">20130404</udt:DateTimeString></ram:DueDateDateTime> + </ram:SpecifiedTradePaymentTerms> + <ram:SpecifiedTradeSettlementMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">473.00</ram:LineTotalAmount> + <ram:ChargeTotalAmount currencyID="EUR">0.00</ram:ChargeTotalAmount> + <ram:AllowanceTotalAmount currencyID="EUR">0.00</ram:AllowanceTotalAmount> + <ram:TaxBasisTotalAmount currencyID="EUR">473.00</ram:TaxBasisTotalAmount> + <ram:TaxTotalAmount currencyID="EUR">56.87</ram:TaxTotalAmount> + <ram:GrandTotalAmount currencyID="EUR">529.87</ram:GrandTotalAmount> + <ram:TotalPrepaidAmount currencyID="EUR">0.00</ram:TotalPrepaidAmount> + <ram:DuePayableAmount currencyID="EUR">529.87</ram:DuePayableAmount> + </ram:SpecifiedTradeSettlementMonetarySummation> + </ram:ApplicableSupplyChainTradeSettlement> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:LineID>1</ram:LineID> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedSupplyChainTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">9.9000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">9.9000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedSupplyChainTradeAgreement> + <ram:SpecifiedSupplyChainTradeDelivery> + <ram:BilledQuantity unitCode="C62">20.0000</ram:BilledQuantity> + </ram:SpecifiedSupplyChainTradeDelivery> + <ram:SpecifiedSupplyChainTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>19.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">198.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementMonetarySummation> + </ram:SpecifiedSupplyChainTradeSettlement> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0160">4012345001235</ram:GlobalID> + <ram:SellerAssignedID>TB100A4</ram:SellerAssignedID> + <ram:Name>Trennblätter A4</ram:Name> + </ram:SpecifiedTradeProduct> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:LineID>2</ram:LineID> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedSupplyChainTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">5.5000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">5.5000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedSupplyChainTradeAgreement> + <ram:SpecifiedSupplyChainTradeDelivery> + <ram:BilledQuantity unitCode="C62">50.0000</ram:BilledQuantity> + </ram:SpecifiedSupplyChainTradeDelivery> + <ram:SpecifiedSupplyChainTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>7.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">275.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementMonetarySummation> + </ram:SpecifiedSupplyChainTradeSettlement> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0160">4000050986428</ram:GlobalID> + <ram:SellerAssignedID>ARNR2</ram:SellerAssignedID> + <ram:Name>Joghurt Banane</ram:Name> + </ram:SpecifiedTradeProduct> + </ram:IncludedSupplyChainTradeLineItem> + </rsm:SpecifiedSupplyChainTradeTransaction> +</rsm:CrossIndustryDocument> \ No newline at end of file diff --git a/src/test/resources/migration/input/ZUGFeRD1_EXTENDED_Warenrechnung.xml b/src/test/resources/migration/input/ZUGFeRD1_EXTENDED_Warenrechnung.xml new file mode 100644 index 00000000..0f26d3ea --- /dev/null +++ b/src/test/resources/migration/input/ZUGFeRD1_EXTENDED_Warenrechnung.xml @@ -0,0 +1,520 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + +Nutzungsrechte +ZUGFeRD Datenformat Version 1.0, 25.6.2014 +Beispiel Version 29.09.2014 + +Zweck des Forums für elektronische Rechnungen bei der AWV e.V („FeRD“) ist u.a. die Schaffung und Spezifizierung +eines offenen Datenformats für strukturierten elektronischen Datenaustausch auf der Grundlage offener und nicht +diskriminierender, standardisierter Technologien („ZUGFeRD Datenformat“) + +Das ZUGFeRD Datenformat wird nach Maßgabe des FeRD sowohl Unternehmen als auch der öffentlichen Verwaltung +frei zugänglich gemacht. Hierfür bietet FeRD allen Unternehmen und Organisationen der öffentlichen Verwaltung eine +Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD-Datenformats zu fairen, sachgerechten und nicht +diskriminierenden Bedingungen an. + +Die Spezifikation des FeRD zur Implementierung des ZUGFeRD Datenformats ist in ihrer jeweils geltenden Fassung +abrufbar unter www.ferd-net.de. + +Im Einzelnen schließt die Nutzungsgewährung ein: +===================================== + +FeRD räumt eine Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD Datenformats in der jeweils +geltenden und akzeptierten Fassung (www.ferd-net.de) ein. +Die Lizenz beinhaltet ein unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, +Weiterbearbeitung und Verbindung mit anderen Produkten. +Die Lizenz gilt insbesondere für die Entwicklung, die Gestaltung, die Herstellung, den Verkauf, die Nutzung oder +anderweitige Verwendung des ZUGFeRD Datenformats für Hardware- und/oder Softwareprodukte sowie sonstige +Anwendungen und Dienste. +Diese Lizenz schließt nicht die wesentlichen Patente der Mitglieder von FeRD ein. Als wesentliche Patente sind Patente +und Patentanmeldungen weltweit zu verstehen, die einen oder mehrere Patentansprüche beinhalten, bei denen es sich um +notwendige Ansprüche handelt. Notwendige Ansprüche sind lediglich jene Ansprüche der Wesentlichen Patente, die durch +die Implementierung des ZUGFeRD Datenformats notwendigerweise verletzt würden. +Der Lizenznehmer ist berechtigt, seinen jeweiligen Konzerngesellschaften ein unbefristetes, weltweites, nicht übertragbares, +unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, Weiterbearbeitung und Verbindung mit +anderen Produkten einzuräumen. + +Die Lizenz wird kostenfrei zur Verfügung gestellt. + +Außer im Falle vorsätzlichen Verschuldens oder grober Fahrlässigkeit haftet FeRD weder für Nutzungsausfall, entgangenen +Gewinn, Datenverlust, Kommunikationsverlust, Einnahmeausfall, Vertragseinbußen, Geschäftsausfall oder für Kosten, +Schäden, Verluste oder Haftpflichten im Zusammenhang mit einer Unterbrechung der Geschäftstätigkeit, noch für konkrete, +beiläufig entstandene, mittelbare Schäden, Straf- oder Folgeschäden und zwar auch dann nicht, wenn die Möglichkeit der +Kosten, Verluste bzw. Schäden hätte normalerweise vorhergesehen werden können. + +--> + +<rsm:CrossIndustryDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rsm="urn:ferd:CrossIndustryDocument:invoice:1p0" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15"> + <rsm:SpecifiedExchangedDocumentContext> + <ram:TestIndicator><udt:Indicator>true</udt:Indicator></ram:TestIndicator><!-- Im Echtbetrieb muss der TestIndicator entweder vollständig entfallen oder auf false stehen. --> + <ram:GuidelineSpecifiedDocumentContextParameter> + <ram:ID>urn:ferd:CrossIndustryDocument:invoice:1p0:extended</ram:ID> + </ram:GuidelineSpecifiedDocumentContextParameter> + </rsm:SpecifiedExchangedDocumentContext> + <rsm:HeaderExchangedDocument> + <ram:ID>R87654321012345</ram:ID> + <ram:Name>WARENRECHNUNG</ram:Name> + <ram:TypeCode>380</ram:TypeCode> + <ram:IssueDateTime> + <udt:DateTimeString format="102">20130806</udt:DateTimeString> + </ram:IssueDateTime> + <ram:IncludedNote> + <ram:ContentCode>ST3</ram:ContentCode> + <ram:Content>Es bestehen Rabatt- oder Bonusvereinbarungen.</ram:Content> + <ram:SubjectCode>AAK</ram:SubjectCode> + </ram:IncludedNote> + <ram:IncludedNote> + <ram:ContentCode>EEV</ram:ContentCode> + <ram:Content>Der Verkäufer bleibt Eigentümer der Waren bis zu vollständigen Erfüllung der Kaufpreisforderung.</ram:Content> + <ram:SubjectCode>AAJ</ram:SubjectCode> + </ram:IncludedNote> + <ram:IncludedNote> + <ram:Content>MUSTERLIEFERANT GMBH +BAHNHOFSTRASSE 99 +99199 MUSTERHAUSEN +Geschäftsführung: +Max Mustermann +USt-IdNr: DE123456789 +Telefon: +49 932 431 0 +www.musterlieferant.de +HRB Nr. 372876 +Amtsgericht Musterstadt +GLN 4304171000002 +WEEE-Reg-Nr.: DE87654321</ram:Content> + <ram:SubjectCode>REG</ram:SubjectCode> + </ram:IncludedNote> + <ram:IncludedNote> + <ram:Content>Leergutwert: 46,50</ram:Content> + </ram:IncludedNote> + </rsm:HeaderExchangedDocument> + <rsm:SpecifiedSupplyChainTradeTransaction> + <ram:ApplicableSupplyChainTradeAgreement> + <ram:SellerTradeParty> + <ram:ID>549910</ram:ID> + <ram:GlobalID schemeID="0088">4333741000005</ram:GlobalID> + <ram:Name>MUSTERLIEFERANT GMBH</ram:Name> + <ram:DefinedTradeContact> + <ram:TelephoneUniversalCommunication> + <ram:CompleteNumber>+49 932 431 500</ram:CompleteNumber> + </ram:TelephoneUniversalCommunication> + <ram:EmailURIUniversalCommunication> + <ram:URIID>max.mustermann@musterlieferant.de</ram:URIID> + </ram:EmailURIUniversalCommunication> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>99199</ram:PostcodeCode> + <ram:LineOne>BAHNHOFSTRASSE 99</ram:LineOne> + <ram:CityName>MUSTERHAUSEN</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">DE123456789</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:SellerTradeParty> + <ram:BuyerTradeParty> + <ram:ID>009420</ram:ID> + <ram:GlobalID schemeID="0088">4304171000002</ram:GlobalID> + <ram:Name>MUSTER-KUNDE GMBH</ram:Name> + <ram:PostalTradeAddress> + <ram:PostcodeCode>40235</ram:PostcodeCode> + <ram:LineOne>KUNDENWEG 88</ram:LineOne> + <ram:CityName>DUESSELDORF</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + </ram:BuyerTradeParty> + <ram:BuyerOrderReferencedDocument> + <ram:IssueDateTime>2013-08-01T00:00:00</ram:IssueDateTime> + <ram:ID>B123456789</ram:ID> + </ram:BuyerOrderReferencedDocument> + <ram:AdditionalReferencedDocument> + <ram:IssueDateTime>2013-08-02T00:00:00</ram:IssueDateTime> + <ram:TypeCode>VN</ram:TypeCode> + <ram:ID>A456123</ram:ID> + </ram:AdditionalReferencedDocument> + </ram:ApplicableSupplyChainTradeAgreement> + <ram:ApplicableSupplyChainTradeDelivery> + <ram:ShipToTradeParty> + <ram:GlobalID schemeID="0088">4304171088093</ram:GlobalID> + <ram:Name>MUSTER-MARKT</ram:Name> + <ram:DefinedTradeContact> + <ram:DepartmentName>8211</ram:DepartmentName> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>31157</ram:PostcodeCode> + <ram:LineOne>HAUPTSTRASSE 44</ram:LineOne> + <ram:CityName>SARSTEDT</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + </ram:ShipToTradeParty> + <ram:ActualDeliverySupplyChainEvent> + <ram:OccurrenceDateTime> + <udt:DateTimeString format="102">20130805</udt:DateTimeString> + </ram:OccurrenceDateTime> + </ram:ActualDeliverySupplyChainEvent> + <ram:DeliveryNoteReferencedDocument> + <ram:IssueDateTime>2013-08-05T00:00:00</ram:IssueDateTime> + <ram:ID>L87654321012345</ram:ID> + </ram:DeliveryNoteReferencedDocument> + </ram:ApplicableSupplyChainTradeDelivery> + <ram:ApplicableSupplyChainTradeSettlement> + <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode> + <ram:InvoiceeTradeParty> + <ram:ID>009420</ram:ID> + <ram:GlobalID schemeID="0088">4304171000002</ram:GlobalID> + <ram:Name>MUSTER-KUNDE GMBH</ram:Name> + <ram:PostalTradeAddress> + <ram:PostcodeCode>40235</ram:PostcodeCode> + <ram:LineOne>KUNDENWEG 88</ram:LineOne> + <ram:CityName>DUESSELDORF</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + </ram:InvoiceeTradeParty> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount currencyID="EUR">61.07</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount currencyID="EUR">321.40</ram:BasisAmount> + <ram:LineTotalBasisAmount currencyID="EUR">326.50</ram:LineTotalBasisAmount> + <ram:AllowanceChargeBasisAmount currencyID="EUR">-5.10</ram:AllowanceChargeBasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>19.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount currencyID="EUR">8.93</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount currencyID="EUR">127.59</ram:BasisAmount> + <ram:LineTotalBasisAmount currencyID="EUR">130.70</ram:LineTotalBasisAmount> + <ram:AllowanceChargeBasisAmount currencyID="EUR">-3.11</ram:AllowanceChargeBasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>7.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator><udt:Indicator>false</udt:Indicator></ram:ChargeIndicator> + <ram:CalculationPercent>2.00</ram:CalculationPercent> + <ram:BasisAmount currencyID="EUR">280.00</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">5.60</ram:ActualAmount> + <ram:Reason>Rechnungsrabatt 1</ram:Reason> + <ram:CategoryTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>19.00</ram:ApplicablePercent> + </ram:CategoryTradeTax> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator><udt:Indicator>false</udt:Indicator></ram:ChargeIndicator> + <ram:CalculationPercent>2.00</ram:CalculationPercent> + <ram:BasisAmount currencyID="EUR">130.70</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">2.61</ram:ActualAmount> + <ram:Reason>Rechnungsrabatt 1</ram:Reason> + <ram:CategoryTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>7.00</ram:ApplicablePercent> + </ram:CategoryTradeTax> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator><udt:Indicator>false</udt:Indicator></ram:ChargeIndicator> + <ram:BasisAmount currencyID="EUR">280.00</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">2.50</ram:ActualAmount> + <ram:Reason>Rechnungsrabatt 2</ram:Reason> + <ram:CategoryTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>19.00</ram:ApplicablePercent> + </ram:CategoryTradeTax> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator><udt:Indicator>false</udt:Indicator></ram:ChargeIndicator> + <ram:BasisAmount currencyID="EUR">130.70</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">0.50</ram:ActualAmount> + <ram:Reason>Rechnungsrabatt 2</ram:Reason> + <ram:CategoryTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>7.00</ram:ApplicablePercent> + </ram:CategoryTradeTax> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedLogisticsServiceCharge> + <ram:Description>Transportkosten</ram:Description> + <ram:AppliedAmount currencyID="EUR">3.00</ram:AppliedAmount> + <ram:AppliedTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>19.00</ram:ApplicablePercent> + </ram:AppliedTradeTax> + </ram:SpecifiedLogisticsServiceCharge> + <ram:SpecifiedTradePaymentTerms> + <ram:Description>Bei Zahlung innerhalb 14 Tagen gewähren wir 2,0% Skonto.</ram:Description> + <ram:ApplicableTradePaymentDiscountTerms> + <ram:BasisPeriodMeasure unitCode="DAY">14</ram:BasisPeriodMeasure> + <ram:CalculationPercent>2.00</ram:CalculationPercent> + </ram:ApplicableTradePaymentDiscountTerms> + </ram:SpecifiedTradePaymentTerms> + <ram:SpecifiedTradeSettlementMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">457.20</ram:LineTotalAmount> + <ram:ChargeTotalAmount currencyID="EUR">3.00</ram:ChargeTotalAmount> + <ram:AllowanceTotalAmount currencyID="EUR">11.21</ram:AllowanceTotalAmount> + <ram:TaxBasisTotalAmount currencyID="EUR">448.99</ram:TaxBasisTotalAmount> + <ram:TaxTotalAmount currencyID="EUR">70.00</ram:TaxTotalAmount> + <ram:GrandTotalAmount currencyID="EUR">518.99</ram:GrandTotalAmount> + <ram:TotalPrepaidAmount currencyID="EUR">0.00</ram:TotalPrepaidAmount> + <ram:DuePayableAmount currencyID="EUR">518.99</ram:DuePayableAmount> + </ram:SpecifiedTradeSettlementMonetarySummation> + </ram:ApplicableSupplyChainTradeSettlement> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:IncludedNote> + <ram:Content>Wichtige Information: Bei Bestellungen bis zum 19.12. ist die Auslieferung bis spätestens 23.12. garantiert.</ram:Content> + </ram:IncludedNote> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedSupplyChainTradeSettlement /> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument /> + <ram:SpecifiedSupplyChainTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">1.0000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">1.0000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedSupplyChainTradeAgreement> + <ram:SpecifiedSupplyChainTradeDelivery> + <ram:BilledQuantity unitCode="C62">100.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="CT">4.0000</ram:PackageQuantity> + </ram:SpecifiedSupplyChainTradeDelivery> + <ram:SpecifiedSupplyChainTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>19.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">100.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementMonetarySummation> + </ram:SpecifiedSupplyChainTradeSettlement> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">4123456000014</ram:GlobalID> + <ram:SellerAssignedID>ZS997</ram:SellerAssignedID> + <ram:Name>Zitronensäure 100ml</ram:Name> + <ram:ApplicableProductCharacteristic> + <ram:TypeCode>PACKAGING_TYPE</ram:TypeCode> + <ram:Description>Verpackungsart</ram:Description> + <ram:Value>BO</ram:Value> + </ram:ApplicableProductCharacteristic> + </ram:SpecifiedTradeProduct> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument /> + <ram:SpecifiedSupplyChainTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">1.5000</ram:ChargeAmount> + <ram:AppliedTradeAllowanceCharge> + <ram:ChargeIndicator><udt:Indicator>false</udt:Indicator></ram:ChargeIndicator> + <ram:CalculationPercent>2.00</ram:CalculationPercent> + <ram:BasisAmount currencyID="EUR">1.5000</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">0.0300</ram:ActualAmount> + <ram:Reason>Artikelrabatt 1</ram:Reason> + </ram:AppliedTradeAllowanceCharge> + <ram:AppliedTradeAllowanceCharge> + <ram:ChargeIndicator><udt:Indicator>false</udt:Indicator></ram:ChargeIndicator> + <ram:BasisQuantity unitCode="C62">1</ram:BasisQuantity> + <ram:ActualAmount currencyID="EUR">0.0200</ram:ActualAmount> + <ram:Reason>Artikelrabatt 2</ram:Reason> + </ram:AppliedTradeAllowanceCharge> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">1.4500</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedSupplyChainTradeAgreement> + <ram:SpecifiedSupplyChainTradeDelivery> + <ram:BilledQuantity unitCode="C62">50.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="CT">1.0000</ram:PackageQuantity> + </ram:SpecifiedSupplyChainTradeDelivery> + <ram:SpecifiedSupplyChainTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>7.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">72.50</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementMonetarySummation> + </ram:SpecifiedSupplyChainTradeSettlement> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">4123456000021</ram:GlobalID> + <ram:SellerAssignedID>GZ250</ram:SellerAssignedID> + <ram:Name>Gelierzucker Extra 250g</ram:Name> + </ram:SpecifiedTradeProduct> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument /> + <ram:SpecifiedSupplyChainTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">0.0000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">0.0000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedSupplyChainTradeAgreement> + <ram:SpecifiedSupplyChainTradeDelivery> + <ram:BilledQuantity unitCode="C62">10.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="CT">1.0000</ram:PackageQuantity> + </ram:SpecifiedSupplyChainTradeDelivery> + <ram:SpecifiedSupplyChainTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>7.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">0.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementMonetarySummation> + </ram:SpecifiedSupplyChainTradeSettlement> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">4123456000021</ram:GlobalID> + <ram:SellerAssignedID>GZ250</ram:SellerAssignedID> + <ram:Name>Gelierzucker Extra 250g</ram:Name> + <ram:Description>Artikel wie vereinbart ohne Berechnung</ram:Description> + </ram:SpecifiedTradeProduct> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:IncludedNote> + <ram:Content>Öko-Kontroll-Nr.: DE-BW-006-987654321054</ram:Content> + <ram:SubjectCode>AAY</ram:SubjectCode> + </ram:IncludedNote> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedSupplyChainTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">12.0000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">12.0000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedSupplyChainTradeAgreement> + <ram:SpecifiedSupplyChainTradeDelivery> + <ram:BilledQuantity unitCode="C62">15.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="BO">20.0000</ram:PackageQuantity> + </ram:SpecifiedSupplyChainTradeDelivery> + <ram:SpecifiedSupplyChainTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>19.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">180.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementMonetarySummation> + </ram:SpecifiedSupplyChainTradeSettlement> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">4100130013294</ram:GlobalID> + <ram:SellerAssignedID>2031</ram:SellerAssignedID> + <ram:BuyerAssignedID>K4321</ram:BuyerAssignedID> + <ram:Name>Bierbrau Pils 20/0500</ram:Name> + <ram:Description>EAN-VKE: 4100130913297</ram:Description> + <ram:ApplicableProductCharacteristic> + <ram:TypeCode>PACKAGING_MATERIAL</ram:TypeCode> + <ram:Description>Verpackung</ram:Description> + <ram:Value>Kiste</ram:Value> + </ram:ApplicableProductCharacteristic> + </ram:SpecifiedTradeProduct> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument /> + <ram:SpecifiedSupplyChainTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">3.1000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">3.1000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedSupplyChainTradeAgreement> + <ram:SpecifiedSupplyChainTradeDelivery> + <ram:BilledQuantity unitCode="C62">15.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="BC">1.0000</ram:PackageQuantity> + </ram:SpecifiedSupplyChainTradeDelivery> + <ram:SpecifiedSupplyChainTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>19.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">46.50</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementMonetarySummation> + </ram:SpecifiedSupplyChainTradeSettlement> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">2001015001325</ram:GlobalID> + <ram:SellerAssignedID>1805</ram:SellerAssignedID> + <ram:BuyerAssignedID>K4322</ram:BuyerAssignedID> + <ram:Name>Leergutpfand 20 x 0,5l</ram:Name> + <ram:ApplicableProductCharacteristic> + <ram:TypeCode>PACKAGING_MATERIAL</ram:TypeCode> + <ram:Description>Verpackung</ram:Description> + <ram:Value>unverpackt</ram:Value> + </ram:ApplicableProductCharacteristic> + </ram:SpecifiedTradeProduct> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument /> + <ram:SpecifiedSupplyChainTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">30.0000</ram:ChargeAmount> + <ram:AppliedTradeAllowanceCharge> + <ram:ChargeIndicator><udt:Indicator>false</udt:Indicator></ram:ChargeIndicator> + <ram:CalculationPercent>3.00</ram:CalculationPercent> + <ram:BasisAmount currencyID="EUR">30.0000</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">0.9000</ram:ActualAmount> + <ram:Reason>Artikelrabatt 1</ram:Reason> + </ram:AppliedTradeAllowanceCharge> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">29.1000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedSupplyChainTradeAgreement> + <ram:SpecifiedSupplyChainTradeDelivery> + <ram:BilledQuantity unitCode="C62">2.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="PX">1.0000</ram:PackageQuantity> + </ram:SpecifiedSupplyChainTradeDelivery> + <ram:SpecifiedSupplyChainTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:ApplicablePercent>7.00</ram:ApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">58.20</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementMonetarySummation> + </ram:SpecifiedSupplyChainTradeSettlement> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">4123456000038</ram:GlobalID> + <ram:SellerAssignedID>MP107</ram:SellerAssignedID> + <ram:Name>Mischpalette Joghurt Karton 3 x 20</ram:Name> + <ram:ApplicableProductCharacteristic> + <ram:TypeCode>PACKAGING_MATERIAL</ram:TypeCode> + <ram:Description>Verpackung</ram:Description> + <ram:Value>Karton</ram:Value> + </ram:ApplicableProductCharacteristic> + <ram:IncludedReferencedProduct> + <ram:GlobalID schemeID="0088">4123456001035</ram:GlobalID> + <ram:SellerAssignedID>JOG103</ram:SellerAssignedID> + <ram:Name>Erdbeer 20 x 150g Becher</ram:Name> + <ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity> + </ram:IncludedReferencedProduct> + <ram:IncludedReferencedProduct> + <ram:GlobalID schemeID="0088">4123456002032</ram:GlobalID> + <ram:SellerAssignedID>JOG203</ram:SellerAssignedID> + <ram:Name>Banane 20 x 150g Becher</ram:Name> + <ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity> + </ram:IncludedReferencedProduct> + <ram:IncludedReferencedProduct> + <ram:GlobalID schemeID="0088">4123456003039</ram:GlobalID> + <ram:SellerAssignedID>JOG303</ram:SellerAssignedID> + <ram:Name>Schoko 20 x 150g Becher</ram:Name> + <ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity> + </ram:IncludedReferencedProduct> + </ram:SpecifiedTradeProduct> + </ram:IncludedSupplyChainTradeLineItem> + </rsm:SpecifiedSupplyChainTradeTransaction> +</rsm:CrossIndustryDocument> diff --git a/src/test/resources/migration/reference/ZUGFeRD2-invoice-adjusted.xml b/src/test/resources/migration/reference/ZUGFeRD2-invoice-adjusted.xml new file mode 100644 index 00000000..770e7dc9 --- /dev/null +++ b/src/test/resources/migration/reference/ZUGFeRD2-invoice-adjusted.xml @@ -0,0 +1,216 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2018 Jochen Staerk + + Use is subject to license terms. + + Licensed under the Apache License, Version 2.0 (the "License"); you may not + use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + See the License for the specific language governing permissions and + limitations under the License. + --> +<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" + xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" + xmlns:qdt="urn:un:unece:uncefact:data:Standard:QualifiedDataType:100" + xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"><!-- +Migrated by Mustangproject XSLT +--><rsm:ExchangedDocumentContext> + <ram:GuidelineSpecifiedDocumentContextParameter> + <ram:ID>urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended</ram:ID> + </ram:GuidelineSpecifiedDocumentContextParameter> + </rsm:ExchangedDocumentContext> + <rsm:ExchangedDocument xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"> + <ram:ID>RE-20170509/506</ram:ID> + <ram:Name>RECHNUNG2</ram:Name> + <ram:TypeCode>380</ram:TypeCode> + <ram:IssueDateTime> + <udt:DateTimeString format="102">20170510</udt:DateTimeString> + </ram:IssueDateTime> + </rsm:ExchangedDocument> + <rsm:SupplyChainTradeTransaction xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:LineID>1</ram:LineID> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedTradeProduct> + <ram:Name>Künstlerische Gestaltung (Stunde): Einer weiteren Beispielrechnung</ram:Name> + <ram:Description/> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">160.0000</ram:ChargeAmount> + <ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">160.0000</ram:ChargeAmount> + <ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="HUR">1.0000</ram:BilledQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">160.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:LineID>2</ram:LineID> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedTradeProduct> + <ram:Name>Luftballon: Bunt, ca. 500ml</ram:Name> + <ram:Description/> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">0.7900</ram:ChargeAmount> + <ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">0.7900</ram:ChargeAmount> + <ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">400.0000</ram:BilledQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">316.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:LineID>3</ram:LineID> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedTradeProduct> + <ram:Name>Heiße Luft pro Liter</ram:Name> + <ram:Description/> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">0.1000</ram:ChargeAmount> + <ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">0.1000</ram:ChargeAmount> + <ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="LTR">200.0000</ram:BilledQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">20.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:ApplicableHeaderTradeAgreement> + <ram:SellerTradeParty> + <ram:Name>Bei Spiel GmbH</ram:Name> + <ram:PostalTradeAddress> + <ram:PostcodeCode>12345</ram:PostcodeCode> + <ram:LineOne>Ecke 12</ram:LineOne> + <ram:CityName>Stadthausen</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="FC">22/815/0815/4</ram:ID> + </ram:SpecifiedTaxRegistration> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">DE136695976</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:SellerTradeParty> + <ram:BuyerTradeParty> + <ram:Name>Theodor Est</ram:Name> + <ram:PostalTradeAddress> + <ram:PostcodeCode>88802</ram:PostcodeCode> + <ram:LineOne>Bahnstr. 42</ram:LineOne> + <ram:CityName>Spielkreis</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">DE999999999</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:BuyerTradeParty> + </ram:ApplicableHeaderTradeAgreement> + <ram:ApplicableHeaderTradeDelivery> + <ram:ActualDeliverySupplyChainEvent> + <ram:OccurrenceDateTime> + <udt:DateTimeString format="102">20170507</udt:DateTimeString> + </ram:OccurrenceDateTime> + </ram:ActualDeliverySupplyChainEvent> + </ram:ApplicableHeaderTradeDelivery> + <ram:ApplicableHeaderTradeSettlement> + <ram:PaymentReference>RE-20170509/505</ram:PaymentReference> + <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode> + <ram:SpecifiedTradeSettlementPaymentMeans> + <ram:TypeCode>42</ram:TypeCode> + <ram:Information>Überweisung</ram:Information> + <ram:PayeePartyCreditorFinancialAccount> + <ram:IBANID>DE88 2008 0000 0970 3757 00</ram:IBANID> + <ram:ProprietaryID>44421800</ram:ProprietaryID> + </ram:PayeePartyCreditorFinancialAccount> + <ram:PayeeSpecifiedCreditorFinancialInstitution> + <ram:BICID>COBADEFFXXX</ram:BICID> + <ram:GermanBankleitzahlID>41441604</ram:GermanBankleitzahlID> + <ram:Name>Commerzbank</ram:Name> + </ram:PayeeSpecifiedCreditorFinancialInstitution> + </ram:SpecifiedTradeSettlementPaymentMeans> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount currencyID="EUR">11.20</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount currencyID="EUR">160.00</ram:BasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount currencyID="EUR">63.84</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount currencyID="EUR">336.00</ram:BasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradePaymentTerms> + <ram:Description>Zahlbar ohne Abzug bis zum 30.05.2017</ram:Description> + <ram:DueDateDateTime> + <udt:DateTimeString format="102">20170530</udt:DateTimeString> + </ram:DueDateDateTime> + </ram:SpecifiedTradePaymentTerms> + <ram:SpecifiedTradeSettlementHeaderMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">496.00</ram:LineTotalAmount> + <ram:ChargeTotalAmount currencyID="EUR">0.00</ram:ChargeTotalAmount> + <ram:AllowanceTotalAmount currencyID="EUR">0.00</ram:AllowanceTotalAmount> + <ram:TaxBasisTotalAmount currencyID="EUR">496.00</ram:TaxBasisTotalAmount> + <ram:TaxTotalAmount currencyID="EUR">75.04</ram:TaxTotalAmount> + <ram:GrandTotalAmount currencyID="EUR">571.04</ram:GrandTotalAmount> + <ram:DuePayableAmount currencyID="EUR">571.04</ram:DuePayableAmount> + </ram:SpecifiedTradeSettlementHeaderMonetarySummation> + </ram:ApplicableHeaderTradeSettlement> + </rsm:SupplyChainTradeTransaction> +</rsm:CrossIndustryInvoice> diff --git a/src/test/resources/migration/reference/ZUGFeRD2-invoice.xml b/src/test/resources/migration/reference/ZUGFeRD2-invoice.xml index b0a390e8..a1ebb2b3 100644 --- a/src/test/resources/migration/reference/ZUGFeRD2-invoice.xml +++ b/src/test/resources/migration/reference/ZUGFeRD2-invoice.xml @@ -21,14 +21,11 @@ xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"> <!--Migrated by Mustangproject XSLT--> <rsm:ExchangedDocumentContext> - <ram:TestIndicator> - <udt:Indicator>false</udt:Indicator> - </ram:TestIndicator> <ram:GuidelineSpecifiedDocumentContextParameter> - <ram:ID>urn:ferd:CrossIndustryDocument:invoice:1p0:extended</ram:ID> + <ram:ID>urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended</ram:ID> </ram:GuidelineSpecifiedDocumentContextParameter> </rsm:ExchangedDocumentContext> - <rsm:ExchangedDocument xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"> + <rsm:ExchangedDocument> <ram:ID>RE-20170509/505</ram:ID> <ram:Name>RECHNUNG</ram:Name> <ram:TypeCode>380</ram:TypeCode> @@ -36,7 +33,7 @@ <udt:DateTimeString format="102">20170509</udt:DateTimeString> </ram:IssueDateTime> </rsm:ExchangedDocument> - <rsm:SupplyChainTradeTransaction xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"> + <rsm:SupplyChainTradeTransaction> <ram:IncludedSupplyChainTradeLineItem> <ram:AssociatedDocumentLineDocument> <ram:LineID>1</ram:LineID> diff --git a/src/test/resources/migration/reference/ZUGFeRD2_COMFORT_Einfach.xml b/src/test/resources/migration/reference/ZUGFeRD2_COMFORT_Einfach.xml new file mode 100644 index 00000000..81432621 --- /dev/null +++ b/src/test/resources/migration/reference/ZUGFeRD2_COMFORT_Einfach.xml @@ -0,0 +1,225 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + +Nutzungsrechte +ZUGFeRD Datenformat Version 1.0, 25.6.2014 +Beispiel Version 29.09.2014 + +Zweck des Forums für elektronische Rechnungen bei der AWV e.V („FeRD“) ist u.a. die Schaffung und Spezifizierung +eines offenen Datenformats für strukturierten elektronischen Datenaustausch auf der Grundlage offener und nicht +diskriminierender, standardisierter Technologien („ZUGFeRD Datenformat“) + +Das ZUGFeRD Datenformat wird nach Maßgabe des FeRD sowohl Unternehmen als auch der öffentlichen Verwaltung +frei zugänglich gemacht. Hierfür bietet FeRD allen Unternehmen und Organisationen der öffentlichen Verwaltung eine +Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD-Datenformats zu fairen, sachgerechten und nicht +diskriminierenden Bedingungen an. + +Die Spezifikation des FeRD zur Implementierung des ZUGFeRD Datenformats ist in ihrer jeweils geltenden Fassung +abrufbar unter www.ferd-net.de. + +Im Einzelnen schließt die Nutzungsgewährung ein: +===================================== + +FeRD räumt eine Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD Datenformats in der jeweils +geltenden und akzeptierten Fassung (www.ferd-net.de) ein. +Die Lizenz beinhaltet ein unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, +Weiterbearbeitung und Verbindung mit anderen Produkten. +Die Lizenz gilt insbesondere für die Entwicklung, die Gestaltung, die Herstellung, den Verkauf, die Nutzung oder +anderweitige Verwendung des ZUGFeRD Datenformats für Hardware- und/oder Softwareprodukte sowie sonstige +Anwendungen und Dienste. +Diese Lizenz schließt nicht die wesentlichen Patente der Mitglieder von FeRD ein. Als wesentliche Patente sind Patente +und Patentanmeldungen weltweit zu verstehen, die einen oder mehrere Patentansprüche beinhalten, bei denen es sich um +notwendige Ansprüche handelt. Notwendige Ansprüche sind lediglich jene Ansprüche der Wesentlichen Patente, die durch +die Implementierung des ZUGFeRD Datenformats notwendigerweise verletzt würden. +Der Lizenznehmer ist berechtigt, seinen jeweiligen Konzerngesellschaften ein unbefristetes, weltweites, nicht übertragbares, +unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, Weiterbearbeitung und Verbindung mit +anderen Produkten einzuräumen. + +Die Lizenz wird kostenfrei zur Verfügung gestellt. + +Außer im Falle vorsätzlichen Verschuldens oder grober Fahrlässigkeit haftet FeRD weder für Nutzungsausfall, entgangenen +Gewinn, Datenverlust, Kommunikationsverlust, Einnahmeausfall, Vertragseinbußen, Geschäftsausfall oder für Kosten, +Schäden, Verluste oder Haftpflichten im Zusammenhang mit einer Unterbrechung der Geschäftstätigkeit, noch für konkrete, +beiläufig entstandene, mittelbare Schäden, Straf- oder Folgeschäden und zwar auch dann nicht, wenn die Möglichkeit der +Kosten, Verluste bzw. Schäden hätte normalerweise vorhergesehen werden können. + +--> +<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" + xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" + xmlns:qdt="urn:un:unece:uncefact:data:Standard:QualifiedDataType:100" + xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"><!-- +Migrated by Mustangproject XSLT +--><rsm:ExchangedDocumentContext> + <ram:GuidelineSpecifiedDocumentContextParameter> + <ram:ID>urn:cen.eu:en16931:2017</ram:ID> + </ram:GuidelineSpecifiedDocumentContextParameter> + </rsm:ExchangedDocumentContext> + <rsm:ExchangedDocument> + <ram:ID>471102</ram:ID> + <ram:Name>RECHNUNG</ram:Name> + <ram:TypeCode>380</ram:TypeCode> + <ram:IssueDateTime> + <udt:DateTimeString format="102">20130305</udt:DateTimeString> + </ram:IssueDateTime> + <ram:IncludedNote> + <ram:Content>Rechnung gemäß Bestellung vom 01.03.2013.</ram:Content> + </ram:IncludedNote> + <ram:IncludedNote> + <ram:Content>Lieferant GmbH +Lieferantenstraße 20 +80333 München +Deutschland +Geschäftsführer: Hans Muster +Handelsregisternummer: H A 123 +</ram:Content> + <ram:SubjectCode>REG</ram:SubjectCode> + </ram:IncludedNote> + </rsm:ExchangedDocument> + <rsm:SupplyChainTradeTransaction> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:LineID>1</ram:LineID> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0160">4012345001235</ram:GlobalID> + <ram:SellerAssignedID>TB100A4</ram:SellerAssignedID> + <ram:Name>Trennblätter A4</ram:Name> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">9.9000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">9.9000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">20.0000</ram:BilledQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">198.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:LineID>2</ram:LineID> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0160">4000050986428</ram:GlobalID> + <ram:SellerAssignedID>ARNR2</ram:SellerAssignedID> + <ram:Name>Joghurt Banane</ram:Name> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">5.5000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">5.5000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">50.0000</ram:BilledQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">275.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:ApplicableHeaderTradeAgreement> + <ram:SellerTradeParty> + <ram:GlobalID schemeID="0088">4000001123452</ram:GlobalID> + <ram:Name>Lieferant GmbH</ram:Name> + <ram:PostalTradeAddress> + <ram:PostcodeCode>80333</ram:PostcodeCode> + <ram:LineOne>Lieferantenstraße 20</ram:LineOne> + <ram:CityName>München</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="FC">201/113/40209</ram:ID> + </ram:SpecifiedTaxRegistration> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">DE123456789</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:SellerTradeParty> + <ram:BuyerTradeParty> + <ram:ID>GE2020211</ram:ID> + <ram:GlobalID schemeID="0088">4000001987658</ram:GlobalID> + <ram:Name>Kunden AG Mitte</ram:Name> + <ram:DefinedTradeContact> + <ram:PersonName>Hans Muster</ram:PersonName> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>69876</ram:PostcodeCode> + <ram:LineOne>Kundenstraße 15</ram:LineOne> + <ram:CityName>Frankfurt</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + </ram:BuyerTradeParty> + </ram:ApplicableHeaderTradeAgreement> + <ram:ApplicableHeaderTradeDelivery> + <ram:ActualDeliverySupplyChainEvent> + <ram:OccurrenceDateTime> + <udt:DateTimeString format="102">20130305</udt:DateTimeString> + </ram:OccurrenceDateTime> + </ram:ActualDeliverySupplyChainEvent> + </ram:ApplicableHeaderTradeDelivery> + <ram:ApplicableHeaderTradeSettlement> + <ram:PaymentReference>2013-471102</ram:PaymentReference> + <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode> + <ram:SpecifiedTradeSettlementPaymentMeans> + <ram:TypeCode>31</ram:TypeCode> + <ram:Information>Überweisung</ram:Information> + <ram:PayeePartyCreditorFinancialAccount> + <ram:IBANID>DE08700901001234567890</ram:IBANID> + </ram:PayeePartyCreditorFinancialAccount> + <ram:PayeeSpecifiedCreditorFinancialInstitution> + <ram:BICID>GENODEF1M04</ram:BICID> + </ram:PayeeSpecifiedCreditorFinancialInstitution> + </ram:SpecifiedTradeSettlementPaymentMeans> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount currencyID="EUR">19.25</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount currencyID="EUR">275.00</ram:BasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount currencyID="EUR">37.62</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount currencyID="EUR">198.00</ram:BasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradePaymentTerms> + <ram:Description>Zahlbar innerhalb 30 Tagen netto bis 04.04.2013, 3% Skonto innerhalb 10 Tagen bis 15.03.2013</ram:Description> + <ram:DueDateDateTime> + <udt:DateTimeString format="102">20130404</udt:DateTimeString> + </ram:DueDateDateTime> + </ram:SpecifiedTradePaymentTerms> + <ram:SpecifiedTradeSettlementHeaderMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">473.00</ram:LineTotalAmount> + <ram:ChargeTotalAmount currencyID="EUR">0.00</ram:ChargeTotalAmount> + <ram:AllowanceTotalAmount currencyID="EUR">0.00</ram:AllowanceTotalAmount> + <ram:TaxBasisTotalAmount currencyID="EUR">473.00</ram:TaxBasisTotalAmount> + <ram:TaxTotalAmount currencyID="EUR">56.87</ram:TaxTotalAmount> + <ram:GrandTotalAmount currencyID="EUR">529.87</ram:GrandTotalAmount> + <ram:TotalPrepaidAmount currencyID="EUR">0.00</ram:TotalPrepaidAmount> + <ram:DuePayableAmount currencyID="EUR">529.87</ram:DuePayableAmount> + </ram:SpecifiedTradeSettlementHeaderMonetarySummation> + </ram:ApplicableHeaderTradeSettlement> + </rsm:SupplyChainTradeTransaction> +</rsm:CrossIndustryInvoice> diff --git a/src/test/resources/migration/reference/ZUGFeRD2_EXTENDED_Warenrechnung.xml b/src/test/resources/migration/reference/ZUGFeRD2_EXTENDED_Warenrechnung.xml new file mode 100644 index 00000000..2ee1b6ea --- /dev/null +++ b/src/test/resources/migration/reference/ZUGFeRD2_EXTENDED_Warenrechnung.xml @@ -0,0 +1,543 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + +Nutzungsrechte +ZUGFeRD Datenformat Version 1.0, 25.6.2014 +Beispiel Version 29.09.2014 + +Zweck des Forums für elektronische Rechnungen bei der AWV e.V („FeRD“) ist u.a. die Schaffung und Spezifizierung +eines offenen Datenformats für strukturierten elektronischen Datenaustausch auf der Grundlage offener und nicht +diskriminierender, standardisierter Technologien („ZUGFeRD Datenformat“) + +Das ZUGFeRD Datenformat wird nach Maßgabe des FeRD sowohl Unternehmen als auch der öffentlichen Verwaltung +frei zugänglich gemacht. Hierfür bietet FeRD allen Unternehmen und Organisationen der öffentlichen Verwaltung eine +Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD-Datenformats zu fairen, sachgerechten und nicht +diskriminierenden Bedingungen an. + +Die Spezifikation des FeRD zur Implementierung des ZUGFeRD Datenformats ist in ihrer jeweils geltenden Fassung +abrufbar unter www.ferd-net.de. + +Im Einzelnen schließt die Nutzungsgewährung ein: +===================================== + +FeRD räumt eine Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD Datenformats in der jeweils +geltenden und akzeptierten Fassung (www.ferd-net.de) ein. +Die Lizenz beinhaltet ein unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, +Weiterbearbeitung und Verbindung mit anderen Produkten. +Die Lizenz gilt insbesondere für die Entwicklung, die Gestaltung, die Herstellung, den Verkauf, die Nutzung oder +anderweitige Verwendung des ZUGFeRD Datenformats für Hardware- und/oder Softwareprodukte sowie sonstige +Anwendungen und Dienste. +Diese Lizenz schließt nicht die wesentlichen Patente der Mitglieder von FeRD ein. Als wesentliche Patente sind Patente +und Patentanmeldungen weltweit zu verstehen, die einen oder mehrere Patentansprüche beinhalten, bei denen es sich um +notwendige Ansprüche handelt. Notwendige Ansprüche sind lediglich jene Ansprüche der Wesentlichen Patente, die durch +die Implementierung des ZUGFeRD Datenformats notwendigerweise verletzt würden. +Der Lizenznehmer ist berechtigt, seinen jeweiligen Konzerngesellschaften ein unbefristetes, weltweites, nicht übertragbares, +unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, Weiterbearbeitung und Verbindung mit +anderen Produkten einzuräumen. + +Die Lizenz wird kostenfrei zur Verfügung gestellt. + +Außer im Falle vorsätzlichen Verschuldens oder grober Fahrlässigkeit haftet FeRD weder für Nutzungsausfall, entgangenen +Gewinn, Datenverlust, Kommunikationsverlust, Einnahmeausfall, Vertragseinbußen, Geschäftsausfall oder für Kosten, +Schäden, Verluste oder Haftpflichten im Zusammenhang mit einer Unterbrechung der Geschäftstätigkeit, noch für konkrete, +beiläufig entstandene, mittelbare Schäden, Straf- oder Folgeschäden und zwar auch dann nicht, wenn die Möglichkeit der +Kosten, Verluste bzw. Schäden hätte normalerweise vorhergesehen werden können. + +--> +<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" + xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" + xmlns:qdt="urn:un:unece:uncefact:data:Standard:QualifiedDataType:100" + xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"><!-- +Migrated by Mustangproject XSLT +--><rsm:ExchangedDocumentContext> + <!-- Im Echtbetrieb muss der TestIndicator entweder vollständig entfallen oder auf false stehen. --> + <ram:GuidelineSpecifiedDocumentContextParameter> + <ram:ID>urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended</ram:ID> + </ram:GuidelineSpecifiedDocumentContextParameter> + </rsm:ExchangedDocumentContext> + <rsm:ExchangedDocument> + <ram:ID>R87654321012345</ram:ID> + <ram:Name>WARENRECHNUNG</ram:Name> + <ram:TypeCode>380</ram:TypeCode> + <ram:IssueDateTime> + <udt:DateTimeString format="102">20130806</udt:DateTimeString> + </ram:IssueDateTime> + <ram:IncludedNote> + <ram:ContentCode>ST3</ram:ContentCode> + <ram:Content>Es bestehen Rabatt- oder Bonusvereinbarungen.</ram:Content> + <ram:SubjectCode>AAK</ram:SubjectCode> + </ram:IncludedNote> + <ram:IncludedNote> + <ram:ContentCode>EEV</ram:ContentCode> + <ram:Content>Der Verkäufer bleibt Eigentümer der Waren bis zu vollständigen Erfüllung der Kaufpreisforderung.</ram:Content> + <ram:SubjectCode>AAJ</ram:SubjectCode> + </ram:IncludedNote> + <ram:IncludedNote> + <ram:Content>MUSTERLIEFERANT GMBH +BAHNHOFSTRASSE 99 +99199 MUSTERHAUSEN +Geschäftsführung: +Max Mustermann +USt-IdNr: DE123456789 +Telefon: +49 932 431 0 +www.musterlieferant.de +HRB Nr. 372876 +Amtsgericht Musterstadt +GLN 4304171000002 +WEEE-Reg-Nr.: DE87654321</ram:Content> + <ram:SubjectCode>REG</ram:SubjectCode> + </ram:IncludedNote> + <ram:IncludedNote> + <ram:Content>Leergutwert: 46,50</ram:Content> + </ram:IncludedNote> + </rsm:ExchangedDocument> + <rsm:SupplyChainTradeTransaction> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:IncludedNote> + <ram:Content>Wichtige Information: Bei Bestellungen bis zum 19.12. ist die Auslieferung bis spätestens 23.12. garantiert.</ram:Content> + </ram:IncludedNote> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedLineTradeSettlement/> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument/> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">4123456000014</ram:GlobalID> + <ram:SellerAssignedID>ZS997</ram:SellerAssignedID> + <ram:Name>Zitronensäure 100ml</ram:Name> + <ram:ApplicableProductCharacteristic> + <ram:TypeCode>PACKAGING_TYPE</ram:TypeCode> + <ram:Description>Verpackungsart</ram:Description> + <ram:Value>BO</ram:Value> + </ram:ApplicableProductCharacteristic> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">1.0000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">1.0000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">100.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="CT">4.0000</ram:PackageQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">100.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument/> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">4123456000021</ram:GlobalID> + <ram:SellerAssignedID>GZ250</ram:SellerAssignedID> + <ram:Name>Gelierzucker Extra 250g</ram:Name> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">1.5000</ram:ChargeAmount> + <ram:AppliedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator>false</udt:Indicator> + </ram:ChargeIndicator> + <ram:CalculationPercent>2.00</ram:CalculationPercent> + <ram:BasisAmount currencyID="EUR">1.5000</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">0.0300</ram:ActualAmount> + <ram:Reason>Artikelrabatt 1</ram:Reason> + </ram:AppliedTradeAllowanceCharge> + <ram:AppliedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator>false</udt:Indicator> + </ram:ChargeIndicator> + <ram:BasisQuantity unitCode="C62">1</ram:BasisQuantity> + <ram:ActualAmount currencyID="EUR">0.0200</ram:ActualAmount> + <ram:Reason>Artikelrabatt 2</ram:Reason> + </ram:AppliedTradeAllowanceCharge> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">1.4500</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">50.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="CT">1.0000</ram:PackageQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">72.50</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument/> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">4123456000021</ram:GlobalID> + <ram:SellerAssignedID>GZ250</ram:SellerAssignedID> + <ram:Name>Gelierzucker Extra 250g</ram:Name> + <ram:Description>Artikel wie vereinbart ohne Berechnung</ram:Description> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">0.0000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">0.0000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">10.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="CT">1.0000</ram:PackageQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">0.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:IncludedNote> + <ram:Content>Öko-Kontroll-Nr.: DE-BW-006-987654321054</ram:Content> + <ram:SubjectCode>AAY</ram:SubjectCode> + </ram:IncludedNote> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">4100130013294</ram:GlobalID> + <ram:SellerAssignedID>2031</ram:SellerAssignedID> + <ram:BuyerAssignedID>K4321</ram:BuyerAssignedID> + <ram:Name>Bierbrau Pils 20/0500</ram:Name> + <ram:Description>EAN-VKE: 4100130913297</ram:Description> + <ram:ApplicableProductCharacteristic> + <ram:TypeCode>PACKAGING_MATERIAL</ram:TypeCode> + <ram:Description>Verpackung</ram:Description> + <ram:Value>Kiste</ram:Value> + </ram:ApplicableProductCharacteristic> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">12.0000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">12.0000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">15.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="BO">20.0000</ram:PackageQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">180.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument/> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">2001015001325</ram:GlobalID> + <ram:SellerAssignedID>1805</ram:SellerAssignedID> + <ram:BuyerAssignedID>K4322</ram:BuyerAssignedID> + <ram:Name>Leergutpfand 20 x 0,5l</ram:Name> + <ram:ApplicableProductCharacteristic> + <ram:TypeCode>PACKAGING_MATERIAL</ram:TypeCode> + <ram:Description>Verpackung</ram:Description> + <ram:Value>unverpackt</ram:Value> + </ram:ApplicableProductCharacteristic> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">3.1000</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">3.1000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">15.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="BC">1.0000</ram:PackageQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">46.50</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument/> + <ram:SpecifiedTradeProduct> + <ram:GlobalID schemeID="0088">4123456000038</ram:GlobalID> + <ram:SellerAssignedID>MP107</ram:SellerAssignedID> + <ram:Name>Mischpalette Joghurt Karton 3 x 20</ram:Name> + <ram:ApplicableProductCharacteristic> + <ram:TypeCode>PACKAGING_MATERIAL</ram:TypeCode> + <ram:Description>Verpackung</ram:Description> + <ram:Value>Karton</ram:Value> + </ram:ApplicableProductCharacteristic> + <ram:IncludedReferencedProduct> + <ram:GlobalID schemeID="0088">4123456001035</ram:GlobalID> + <ram:SellerAssignedID>JOG103</ram:SellerAssignedID> + <ram:Name>Erdbeer 20 x 150g Becher</ram:Name> + <ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity> + </ram:IncludedReferencedProduct> + <ram:IncludedReferencedProduct> + <ram:GlobalID schemeID="0088">4123456002032</ram:GlobalID> + <ram:SellerAssignedID>JOG203</ram:SellerAssignedID> + <ram:Name>Banane 20 x 150g Becher</ram:Name> + <ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity> + </ram:IncludedReferencedProduct> + <ram:IncludedReferencedProduct> + <ram:GlobalID schemeID="0088">4123456003039</ram:GlobalID> + <ram:SellerAssignedID>JOG303</ram:SellerAssignedID> + <ram:Name>Schoko 20 x 150g Becher</ram:Name> + <ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity> + </ram:IncludedReferencedProduct> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">30.0000</ram:ChargeAmount> + <ram:AppliedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator>false</udt:Indicator> + </ram:ChargeIndicator> + <ram:CalculationPercent>3.00</ram:CalculationPercent> + <ram:BasisAmount currencyID="EUR">30.0000</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">0.9000</ram:ActualAmount> + <ram:Reason>Artikelrabatt 1</ram:Reason> + </ram:AppliedTradeAllowanceCharge> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount currencyID="EUR">29.1000</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">2.0000</ram:BilledQuantity> + <ram:PackageQuantity unitCode="PX">1.0000</ram:PackageQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">58.20</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:ApplicableHeaderTradeAgreement> + <ram:SellerTradeParty> + <ram:ID>549910</ram:ID> + <ram:GlobalID schemeID="0088">4333741000005</ram:GlobalID> + <ram:Name>MUSTERLIEFERANT GMBH</ram:Name> + <ram:DefinedTradeContact> + <ram:TelephoneUniversalCommunication> + <ram:CompleteNumber>+49 932 431 500</ram:CompleteNumber> + </ram:TelephoneUniversalCommunication> + <ram:EmailURIUniversalCommunication> + <ram:URIID>max.mustermann@musterlieferant.de</ram:URIID> + </ram:EmailURIUniversalCommunication> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>99199</ram:PostcodeCode> + <ram:LineOne>BAHNHOFSTRASSE 99</ram:LineOne> + <ram:CityName>MUSTERHAUSEN</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">DE123456789</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:SellerTradeParty> + <ram:BuyerTradeParty> + <ram:ID>009420</ram:ID> + <ram:GlobalID schemeID="0088">4304171000002</ram:GlobalID> + <ram:Name>MUSTER-KUNDE GMBH</ram:Name> + <ram:PostalTradeAddress> + <ram:PostcodeCode>40235</ram:PostcodeCode> + <ram:LineOne>KUNDENWEG 88</ram:LineOne> + <ram:CityName>DUESSELDORF</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + </ram:BuyerTradeParty> + <ram:BuyerOrderReferencedDocument> + <ram:IssuerAssignedID>B123456789</ram:IssuerAssignedID> + <ram:FormattedIssueDateTime> + <qdt:DateTimeString>2013-08-01T00:00:00</qdt:DateTimeString> + </ram:FormattedIssueDateTime> + </ram:BuyerOrderReferencedDocument> + <ram:AdditionalReferencedDocument> + <ram:IssuerAssignedID>A456123</ram:IssuerAssignedID> + <ram:TypeCode>VN</ram:TypeCode> + <ram:FormattedIssueDateTime> + <qdt:DateTimeString>2013-08-02T00:00:00</qdt:DateTimeString> + </ram:FormattedIssueDateTime> + </ram:AdditionalReferencedDocument> + </ram:ApplicableHeaderTradeAgreement> + <ram:ApplicableHeaderTradeDelivery> + <ram:ShipToTradeParty> + <ram:GlobalID schemeID="0088">4304171088093</ram:GlobalID> + <ram:Name>MUSTER-MARKT</ram:Name> + <ram:DefinedTradeContact> + <ram:DepartmentName>8211</ram:DepartmentName> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>31157</ram:PostcodeCode> + <ram:LineOne>HAUPTSTRASSE 44</ram:LineOne> + <ram:CityName>SARSTEDT</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + </ram:ShipToTradeParty> + <ram:ActualDeliverySupplyChainEvent> + <ram:OccurrenceDateTime> + <udt:DateTimeString format="102">20130805</udt:DateTimeString> + </ram:OccurrenceDateTime> + </ram:ActualDeliverySupplyChainEvent> + <ram:DeliveryNoteReferencedDocument> + <ram:IssuerAssignedID>L87654321012345</ram:IssuerAssignedID> + <ram:FormattedIssueDateTime> + <qdt:DateTimeString>2013-08-05T00:00:00</qdt:DateTimeString> + </ram:FormattedIssueDateTime> + </ram:DeliveryNoteReferencedDocument> + </ram:ApplicableHeaderTradeDelivery> + <ram:ApplicableHeaderTradeSettlement> + <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode> + <ram:InvoiceeTradeParty> + <ram:ID>009420</ram:ID> + <ram:GlobalID schemeID="0088">4304171000002</ram:GlobalID> + <ram:Name>MUSTER-KUNDE GMBH</ram:Name> + <ram:PostalTradeAddress> + <ram:PostcodeCode>40235</ram:PostcodeCode> + <ram:LineOne>KUNDENWEG 88</ram:LineOne> + <ram:CityName>DUESSELDORF</ram:CityName> + <ram:CountryID>DE</ram:CountryID> + </ram:PostalTradeAddress> + </ram:InvoiceeTradeParty> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount currencyID="EUR">61.07</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount currencyID="EUR">321.40</ram:BasisAmount> + <ram:LineTotalBasisAmount currencyID="EUR">326.50</ram:LineTotalBasisAmount> + <ram:AllowanceChargeBasisAmount currencyID="EUR">-5.10</ram:AllowanceChargeBasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount currencyID="EUR">8.93</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount currencyID="EUR">127.59</ram:BasisAmount> + <ram:LineTotalBasisAmount currencyID="EUR">130.70</ram:LineTotalBasisAmount> + <ram:AllowanceChargeBasisAmount currencyID="EUR">-3.11</ram:AllowanceChargeBasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator>false</udt:Indicator> + </ram:ChargeIndicator> + <ram:CalculationPercent>2.00</ram:CalculationPercent> + <ram:BasisAmount currencyID="EUR">280.00</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">5.60</ram:ActualAmount> + <ram:Reason>Rechnungsrabatt 1</ram:Reason> + <ram:CategoryTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:CategoryTradeTax> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator>false</udt:Indicator> + </ram:ChargeIndicator> + <ram:CalculationPercent>2.00</ram:CalculationPercent> + <ram:BasisAmount currencyID="EUR">130.70</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">2.61</ram:ActualAmount> + <ram:Reason>Rechnungsrabatt 1</ram:Reason> + <ram:CategoryTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent> + </ram:CategoryTradeTax> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator>false</udt:Indicator> + </ram:ChargeIndicator> + <ram:BasisAmount currencyID="EUR">280.00</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">2.50</ram:ActualAmount> + <ram:Reason>Rechnungsrabatt 2</ram:Reason> + <ram:CategoryTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:CategoryTradeTax> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator>false</udt:Indicator> + </ram:ChargeIndicator> + <ram:BasisAmount currencyID="EUR">130.70</ram:BasisAmount> + <ram:ActualAmount currencyID="EUR">0.50</ram:ActualAmount> + <ram:Reason>Rechnungsrabatt 2</ram:Reason> + <ram:CategoryTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent> + </ram:CategoryTradeTax> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedLogisticsServiceCharge> + <ram:Description>Transportkosten</ram:Description> + <ram:AppliedAmount currencyID="EUR">3.00</ram:AppliedAmount> + <ram:AppliedTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent> + </ram:AppliedTradeTax> + </ram:SpecifiedLogisticsServiceCharge> + <ram:SpecifiedTradePaymentTerms> + <ram:Description>Bei Zahlung innerhalb 14 Tagen gewähren wir 2,0% Skonto.</ram:Description> + <ram:ApplicableTradePaymentDiscountTerms> + <ram:BasisPeriodMeasure unitCode="DAY">14</ram:BasisPeriodMeasure> + <ram:CalculationPercent>2.00</ram:CalculationPercent> + </ram:ApplicableTradePaymentDiscountTerms> + </ram:SpecifiedTradePaymentTerms> + <ram:SpecifiedTradeSettlementHeaderMonetarySummation> + <ram:LineTotalAmount currencyID="EUR">457.20</ram:LineTotalAmount> + <ram:ChargeTotalAmount currencyID="EUR">3.00</ram:ChargeTotalAmount> + <ram:AllowanceTotalAmount currencyID="EUR">11.21</ram:AllowanceTotalAmount> + <ram:TaxBasisTotalAmount currencyID="EUR">448.99</ram:TaxBasisTotalAmount> + <ram:TaxTotalAmount currencyID="EUR">70.00</ram:TaxTotalAmount> + <ram:GrandTotalAmount currencyID="EUR">518.99</ram:GrandTotalAmount> + <ram:TotalPrepaidAmount currencyID="EUR">0.00</ram:TotalPrepaidAmount> + <ram:DuePayableAmount currencyID="EUR">518.99</ram:DuePayableAmount> + </ram:SpecifiedTradeSettlementHeaderMonetarySummation> + </ram:ApplicableHeaderTradeSettlement> + </rsm:SupplyChainTradeTransaction> +</rsm:CrossIndustryInvoice>