From 43e63e126f580a6fdf07745ccf091e8596e35a16 Mon Sep 17 00:00:00 2001 From: Svante Schubert Date: Sun, 29 Apr 2018 12:08:38 +0200 Subject: [PATCH] Fixing ZUGFeRD 1.0 to 2.0 XSL transformation by adding latest SAXON. In addition, adding JUnit test, some copyright header, etc. --- ZUGFeRD2-invoice.xml | 202 ++++++ dependency-reduced-pom.xml | 60 +- pom.xml | 573 +++++++++--------- .../ZUGFeRD/ZUGFeRDMigrator.java | 142 +++-- .../org/mustangproject/toecount/Toecount.java | 77 +-- .../ZUGFeRD/UpdateZUGFeRDTest.java | 88 +++ .../resources/ZUGFeRD1-invoice_test-input.xml | 197 ++++++ .../ZUGFeRD2-invoice_output-reference.xml | 202 ++++++ 8 files changed, 1139 insertions(+), 402 deletions(-) create mode 100644 ZUGFeRD2-invoice.xml create mode 100644 src/test/java/org/mustangproject/ZUGFeRD/UpdateZUGFeRDTest.java create mode 100644 src/test/resources/ZUGFeRD1-invoice_test-input.xml create mode 100644 src/test/resources/ZUGFeRD2-invoice_output-reference.xml diff --git a/ZUGFeRD2-invoice.xml b/ZUGFeRD2-invoice.xml new file mode 100644 index 00000000..cf4be5c7 --- /dev/null +++ b/ZUGFeRD2-invoice.xml @@ -0,0 +1,202 @@ + + + + false + + + urn:ferd:CrossIndustryDocument:invoice:1p0:extended + + + + RE-20170509/505 + RECHNUNG + 380 + + 20170509 + + + + + + 1 + + + Künstlerische Gestaltung (Stunde): Einer Beispielrechnung + + + + + 160.0000 + 1.0000 + + + 160.0000 + 1.0000 + + + + 1.0000 + + + + VAT + S + 7.00 + + + 160.00 + + + + + + 2 + + + Luftballon: Bunt, ca. 500ml + + + + + 0.7900 + 1.0000 + + + 0.7900 + 1.0000 + + + + 400.0000 + + + + VAT + S + 19.00 + + + 316.00 + + + + + + 3 + + + Heiße Luft pro Liter + + + + + 0.1000 + 1.0000 + + + 0.1000 + 1.0000 + + + + 200.0000 + + + + VAT + S + 19.00 + + + 20.00 + + + + + + Bei Spiel GmbH + + 12345 + Ecke 12 + Stadthausen + DE + + + 22/815/0815/4 + + + DE136695976 + + + + Theodor Est + + 88802 + Bahnstr. 42 + Spielkreis + DE + + + DE999999999 + + + + + + + 20170507 + + + + + RE-20170509/505 + EUR + + 42 + Überweisung + + DE88 2008 0000 0970 3757 00 + + + COBADEFFXXX + Commerzbank + + + + 11.20 + VAT + 160.00 + S + 7.00 + + + 63.84 + VAT + 336.00 + S + 19.00 + + + Zahlbar ohne Abzug bis zum 30.05.2017 + + 20170530 + + + + 496.00 + 0.00 + 0.00 + 496.00 + 75.04 + 571.04 + 571.04 + + + + + diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml index 9098a2dd..ee13d637 100644 --- a/dependency-reduced-pom.xml +++ b/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ org.mustangproject.ZUGFeRD mustang Mustang - 1.4.2-SNAPSHOT + 1.5.2-SNAPSHOT The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs http://www.mustangproject.org/ @@ -41,24 +41,19 @@ scm:git:https://github.com/ZUGFeRD/mustangproject.git scm:git:https://github.com/ZUGFeRD/mustangproject.git - v1.4.0 + mustang-1.5.0 https://github.com/ZUGFeRD/mustangproject + + + + maven-release-plugin + 2.5.3 + + + - - maven-assembly-plugin - - - - org.mustangproject.toecount.Toecount - - - - jar-with-dependencies - - - maven-compiler-plugin 2.3.2 @@ -86,7 +81,7 @@ com.github.github site-maven-plugin - 0.11 + 0.12 deploy @@ -125,7 +120,38 @@ + + + org.mustangproject.toecount.Toecount + + true + + + log4j:log4j + + ** + + + + commons-logging:commons-logging + + ** + + + + com.sun.xml.bind:jaxb-impl + + ** + + + + com.sun.xml.bind:jaxb-core + + ** + + + @@ -157,7 +183,7 @@ 2.1 org.mustangproject.ZUGFeRD.model - src/main/schema/ZUGFeRD1p0.xsd + src/main/resources/schema/ZUGFeRD1p0.xsd diff --git a/pom.xml b/pom.xml index c47465db..623f3e86 100644 --- a/pom.xml +++ b/pom.xml @@ -1,293 +1,298 @@ - 4.0.0 - org.mustangproject.ZUGFeRD - mustang - 1.5.2-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.0 - - - - 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.7 - 1.7 - 1.7 - - + 4.0.0 + org.mustangproject.ZUGFeRD + mustang + 1.5.2-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.0 + + + + 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.7 + 1.7 + 1.7 + + + + + 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.5 + + + org.apache.pdfbox + pdfbox + 2.0.5 + + + junit + junit + 4.12 + test + + + com.helger + ph-schematron + 4.3.1 + test + + + + com.sanityinc + jargs + 2.0-SNAPSHOT + - - 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.5 - - - org.apache.pdfbox - pdfbox - 2.0.5 - - - junit - junit - 4.11 - test - - - com.helger - ph-schematron - 4.3.1 - test - - - - 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 - 2.3.2 - - - - true - org.mustangproject.toecount.Toecount - - - - jar-with-dependencies - - - - 1.7 - 1.7 - - + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + + + true + org.mustangproject.toecount.Toecount + + + + jar-with-dependencies + + + + 1.7 + 1.7 + + - - - 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 - - - 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 - - - + + + 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 + + + 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 + + + diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java index df5069e5..e6aeca5c 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDMigrator.java @@ -1,89 +1,99 @@ +/** ********************************************************************** + * + * 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. You can also + * obtain a copy of the License at http://odftoolkit.org/docs/license.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ package org.mustangproject.ZUGFeRD; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; - +import java.util.logging.Level; +import java.util.logging.Logger; import javax.xml.transform.Source; +import javax.xml.transform.Templates; import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.URIResolver; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; - - public class ZUGFeRDMigrator { - static final ClassLoader cl = ZUGFeRDMigrator.class.getClassLoader(); - private static TransformerFactory factory = null; - private static final String resourcePath = ""; //$NON-NLS-1$ - private static TransformerFactory getTransformerFactory() { - //TransformerFactory fact = new net.sf.saxon.TransformerFactoryImpl(); - TransformerFactory fact = TransformerFactory.newInstance(); - fact.setURIResolver(new ClasspathResourceURIResolver()); - return fact; - } - public String migrateFromV1ToV2(String xmlFilename) { -/*** - * 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 - */ - ByteArrayOutputStream baos=new ByteArrayOutputStream(); - try { - applySchematronXsl(new FileInputStream(xmlFilename), baos); - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (TransformerException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - String res=null; - try { - res=baos.toString("UTF-8"); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return res; - } + static final ClassLoader CLASS_LOADER = ZUGFeRDMigrator.class.getClassLoader(); + private static final String RESOURCE_PATH = ""; //$NON-NLS-1$ + private static final Logger LOG = Logger.getLogger(ZUGFeRDMigrator.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 mXsltTemplate = null; - 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(); + public ZUGFeRDMigrator() { + mFactory = new net.sf.saxon.TransformerFactoryImpl(); + //fact = TransformerFactory.newInstance(); + mFactory.setURIResolver(new ClasspathResourceURIResolver()); + try { + mXsltTemplate = mFactory.newTemplates(new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "COMFORTtoEN16931.xsl"))); + } catch (TransformerConfigurationException ex) { + LOG.log(Level.SEVERE, null, ex); + } + } - try (FileOutputStream fos = new FileOutputStream(result)) { - transformer.transform(toTransform, new StreamResult(fos)); - } - return result; - } - - private static class ClasspathResourceURIResolver implements URIResolver { - ClasspathResourceURIResolver() { - // Do nothing, just prevents synthetic access warning. - } + public String migrateFromV1ToV2(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 + */ + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + applySchematronXsl(new FileInputStream(xmlFilename), baos); + String res = null; + res = baos.toString("UTF-8"); + return res; + } - @Override - public Source resolve(String href, String base) throws TransformerException { - return new StreamSource(cl.getResourceAsStream(resourcePath + href)); - } - } - - public static void applySchematronXsl(final InputStream xmlFile, - final OutputStream EN16931Outstream) throws TransformerException { - factory=getTransformerFactory(); - Transformer transformer = factory.newTransformer(new StreamSource(cl.getResourceAsStream(resourcePath+"COMFORTtoEN16931.xsl"))); - transformer.transform(new StreamSource(xmlFile), new StreamResult(EN16931Outstream)); - } + public void applySchematronXsl(final InputStream xmlFile, + final OutputStream EN16931Outstream) throws TransformerException { + Transformer transformer = mXsltTemplate.newTransformer(); + transformer.transform(new StreamSource(xmlFile), new StreamResult(EN16931Outstream)); + } + 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/toecount/Toecount.java b/src/main/java/org/mustangproject/toecount/Toecount.java index fea91d50..1f10c108 100755 --- a/src/main/java/org/mustangproject/toecount/Toecount.java +++ b/src/main/java/org/mustangproject/toecount/Toecount.java @@ -2,17 +2,23 @@ package org.mustangproject.toecount; /*** * This is the command line interface to mustangproject - * + * */ +import com.sanityinc.jargs.CmdLineParser; +import com.sanityinc.jargs.CmdLineParser.Option; import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; - +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.xml.transform.TransformerException; import org.mustangproject.ZUGFeRD.ZUGFeRDConformanceLevel; import org.mustangproject.ZUGFeRD.ZUGFeRDExporter; import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1Factory; @@ -20,9 +26,6 @@ import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA3Factory; import org.mustangproject.ZUGFeRD.ZUGFeRDImporter; import org.mustangproject.ZUGFeRD.ZUGFeRDMigrator; -import com.sanityinc.jargs.CmdLineParser; -import com.sanityinc.jargs.CmdLineParser.Option; - public class Toecount { // build with: /opt/local/bin/mvn clean compile assembly:single private static void printUsage() { @@ -53,7 +56,7 @@ public class Toecount { /*** * Asks the user for a String (offering a defaultValue) conforming to a Regex * pattern - * + * * @param prompt * @param defaultValue * @param pattern @@ -98,10 +101,10 @@ public class Toecount { * Prompts the user for a input or output filename * @param prompt * @param defaultFilename - * @param expectedExtension will warn if filename does not match expected file extension + * @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) { @@ -147,7 +150,7 @@ public class Toecount { System.out.println("File does not exist, try again or CTRL+C to cancel"); // discard the input, a scanner.reset is not sufficient fileExistenceOK = false; - } + } } else { fileExistenceOK=true; @@ -158,7 +161,7 @@ public class Toecount { System.out.println("Output file already exists, try again or CTRL+C to cancel"); // discard the input, a scanner.reset is not sufficient - } + } } else { fileExistenceOK=true; } @@ -275,12 +278,12 @@ public class Toecount { String versionInput = ""; try { versionInput = getStringFromUser("ZUGFeRD version (1 or 2)", "1", "1|2"); - + } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - + String profileInput = ""; int zfIntVersion=Integer.valueOf(versionInput); @@ -288,7 +291,7 @@ public class Toecount { if (zfIntVersion==1) { try { profileInput = getStringFromUser("ZUGFeRD profile b)asic, c)omfort or e)xtended", "e", "B|b|C|c|E|e").toLowerCase(); - + } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -296,17 +299,17 @@ public class Toecount { if (profileInput.equals("b")) { profile=ZUGFeRDConformanceLevel.BASIC; } else if (profileInput.equals("c")) { - profile=ZUGFeRDConformanceLevel.COMFORT; + profile=ZUGFeRDConformanceLevel.COMFORT; } else if (profileInput.equals("e")) { profile=ZUGFeRDConformanceLevel.EXTENDED; - + } - + } else if (zfIntVersion==2) { try { - profileInput = getStringFromUser("ZUGFeRD profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + + profileInput = 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|").toLowerCase(); - + } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -314,7 +317,7 @@ public class Toecount { if (profileInput.equals("m")) { profile=ZUGFeRDConformanceLevel.MINIMUM; } else if (profileInput.equals("w")) { - profile=ZUGFeRDConformanceLevel.BASICWL; + profile=ZUGFeRDConformanceLevel.BASICWL; } else if (profileInput.equals("b")) { profile=ZUGFeRDConformanceLevel.BASIC; } else if (profileInput.equals("c")) { @@ -324,13 +327,13 @@ public class Toecount { } else if (profileInput.equals("x")) { profile=ZUGFeRDConformanceLevel.EXTENDED; } - + } - + ZUGFeRDExporter ze = new ZUGFeRDExporterFromA3Factory().setProducer("Toecount") .setCreator(System.getProperty("user.name")).setZUGFeRDConformanceLevel(profile).load(pdfName); ze.setZUGFeRDVersion(zfIntVersion); - + ze.setZUGFeRDXMLData(Files.readAllBytes(Paths.get(xmlName))); ze.export(outName); @@ -373,21 +376,25 @@ public class Toecount { } System.out.println("Written to " + outName); } else if (upgradeRequested) { - String xmlName = ""; - String outName = ""; + try { + String xmlName = ""; + String outName = ""; - try { - xmlName = getFilenameFromUser("ZUGFeRD 1.0 XML source", "ZUGFeRD-invoice.xml", "xml", true, false); - outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "factur-x.xml", "xml", false, true); - - ZUGFeRDMigrator zmi = new ZUGFeRDMigrator(); - String xml = zmi.migrateFromV1ToV2(xmlName); - Files.write(Paths.get(outName), xml.getBytes()); - } catch (IOException e) { - e.printStackTrace(); - } - System.out.println("Written to " + outName); + xmlName = getFilenameFromUser("ZUGFeRD 1.0 XML source", "ZUGFeRD-invoice.xml", "xml", true, false); + outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "factur-x.xml", "xml", false, true); + ZUGFeRDMigrator zmi = new ZUGFeRDMigrator(); + String xml = null; + xml = zmi.migrateFromV1ToV2(xmlName); + Files.write(Paths.get(outName), xml.getBytes()); + System.out.println("Written to " + outName); + } catch (FileNotFoundException ex) { + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, ex); + } catch (TransformerException | UnsupportedEncodingException ex) { + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, ex); + } catch (IOException ex) { + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, ex); + } } else { // no argument or argument unknown printUsage(); diff --git a/src/test/java/org/mustangproject/ZUGFeRD/UpdateZUGFeRDTest.java b/src/test/java/org/mustangproject/ZUGFeRD/UpdateZUGFeRDTest.java new file mode 100644 index 00000000..a45abcb1 --- /dev/null +++ b/src/test/java/org/mustangproject/ZUGFeRD/UpdateZUGFeRDTest.java @@ -0,0 +1,88 @@ +/** ********************************************************************** + * + * 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. You can also + * obtain a copy of the License at http://odftoolkit.org/docs/license.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + *********************************************************************** */ +package org.mustangproject.ZUGFeRD; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.xml.transform.TransformerException; +import org.junit.Assert; +import org.junit.Test; + +public class UpdateZUGFeRDTest { + + private static final Logger LOG = Logger.getLogger(UpdateZUGFeRDTest.class.getName()); + + private static final String TEST_INPUT_NAME = "ZUGFeRD1-invoice_test-input.xml"; + private static final String TEST_OUTPUT_NAME = "ZUGFeRD2-invoice_test-output.xml"; + private static final String TEST_REF_NAME = "ZUGFeRD2-invoice_output-reference.xml"; + + private static final String TEST_INPUT_DIR = "src" + File.separator + "test" + File.separator + "resources" + File.separator; + private static final String TEST_OUTPUT_DIR = "target" + File.separator + "test-classes" + File.separator; + + private static String readFile(Charset encoding, String path) throws IOException { + byte[] encoded = Files.readAllBytes(Paths.get(path)); + return new String(encoded, encoding); + } + + private static void saveFile(String content, String path) throws FileNotFoundException { + try (PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File(path)), StandardCharsets.UTF_8), true)) { + out.println(content); + } + } + + @Test + public void testMigration() { + try { + String tmp = new ZUGFeRDMigrator().migrateFromV1ToV2(TEST_INPUT_DIR + TEST_INPUT_NAME); + saveFile(tmp, TEST_OUTPUT_DIR + TEST_OUTPUT_NAME); + LOG.log(Level.INFO, "***\nZUGFeRD 2.0:\n***\n{0}", tmp); + + // we need to save the string and reload it otherwise two bytes are missing (likely EOF related) + String refXML = readFile(StandardCharsets.UTF_8, TEST_INPUT_DIR + TEST_REF_NAME); + String outXML = readFile(StandardCharsets.UTF_8, TEST_OUTPUT_DIR + TEST_OUTPUT_NAME); + int t = outXML.length(); + int r = refXML.length(); + if (t != r || !(outXML.equals(refXML))) { + LOG.info("Please compare:" + + "\nZUGFeRD 2.0 Test Output: " + TEST_OUTPUT_DIR + TEST_OUTPUT_NAME + + "\nZUGFeRD 2.0 Test Reference: " + TEST_INPUT_DIR + TEST_REF_NAME); + LOG.info("\n\nFile sizes:\n " + + "\nZUGFeRD 2.0 Test Output: " + t + + "\nZUGFeRD 2.0 Test Reference: " + r); + Assert.fail("Version update failed, as test result and reference are different!"); + }else{ + LOG.log(Level.INFO, "***\nZUGFeRD 2.0 invoice:\n***\n{0}", outXML); + } + } catch (IOException | TransformerException t) { + LOG.log(Level.SEVERE, t.getMessage(), t); + Assert.fail("Failed with " + t.getClass().getName() + ": '" + t.getMessage() + "'"); + } + } +} diff --git a/src/test/resources/ZUGFeRD1-invoice_test-input.xml b/src/test/resources/ZUGFeRD1-invoice_test-input.xml new file mode 100644 index 00000000..acfa8950 --- /dev/null +++ b/src/test/resources/ZUGFeRD1-invoice_test-input.xml @@ -0,0 +1,197 @@ + + + + + false + + + urn:ferd:CrossIndustryDocument:invoice:1p0:extended + + + + RE-20170509/505 + RECHNUNG + 380 + + 20170509 + + + + + + Bei Spiel GmbH + + 12345 + Ecke 12 + Stadthausen + DE + + + 22/815/0815/4 + + + DE136695976 + + + + Theodor Est + + 88802 + Bahnstr. 42 + Spielkreis + DE + + + DE999999999 + + + + + + + 20170507 + + + + + RE-20170509/505 + EUR + + 42 + Überweisung + + DE88 2008 0000 0970 3757 00 + + + COBADEFFXXX + Commerzbank + + + + 11.20 + VAT + 160.00 + S + 7.00 + + + 63.84 + VAT + 336.00 + S + 19.00 + + + Zahlbar ohne Abzug bis zum 30.05.2017 + + 20170530 + + + + 496.00 + 0.00 + 0.00 + 496.00 + 75.04 + 571.04 + 571.04 + + + + + 1 + + + + 160.0000 + 1.0000 + + + 160.0000 + 1.0000 + + + + 1.0000 + + + + VAT + S + 7.00 + + + 160.00 + + + + Künstlerische Gestaltung (Stunde): Einer Beispielrechnung + + + + + + 2 + + + + 0.7900 + 1.0000 + + + 0.7900 + 1.0000 + + + + 400.0000 + + + + VAT + S + 19.00 + + + 316.00 + + + + Luftballon: Bunt, ca. 500ml + + + + + + 3 + + + + 0.1000 + 1.0000 + + + 0.1000 + 1.0000 + + + + 200.0000 + + + + VAT + S + 19.00 + + + 20.00 + + + + Heiße Luft pro Liter + + + + + diff --git a/src/test/resources/ZUGFeRD2-invoice_output-reference.xml b/src/test/resources/ZUGFeRD2-invoice_output-reference.xml new file mode 100644 index 00000000..c379c2c1 --- /dev/null +++ b/src/test/resources/ZUGFeRD2-invoice_output-reference.xml @@ -0,0 +1,202 @@ + + + + false + + + urn:ferd:CrossIndustryDocument:invoice:1p0:extended + + + + RE-20170509/505 + RECHNUNG + 380 + + 20170509 + + + + + + 1 + + + Künstlerische Gestaltung (Stunde): Einer Beispielrechnung + + + + + 160.0000 + 1.0000 + + + 160.0000 + 1.0000 + + + + 1.0000 + + + + VAT + S + 7.00 + + + 160.00 + + + + + + 2 + + + Luftballon: Bunt, ca. 500ml + + + + + 0.7900 + 1.0000 + + + 0.7900 + 1.0000 + + + + 400.0000 + + + + VAT + S + 19.00 + + + 316.00 + + + + + + 3 + + + Heiße Luft pro Liter + + + + + 0.1000 + 1.0000 + + + 0.1000 + 1.0000 + + + + 200.0000 + + + + VAT + S + 19.00 + + + 20.00 + + + + + + Bei Spiel GmbH + + 12345 + Ecke 12 + Stadthausen + DE + + + 22/815/0815/4 + + + DE136695976 + + + + Theodor Est + + 88802 + Bahnstr. 42 + Spielkreis + DE + + + DE999999999 + + + + + + + 20170507 + + + + + RE-20170509/505 + EUR + + 42 + Überweisung + + DE88 2008 0000 0970 3757 00 + + + COBADEFFXXX + Commerzbank + + + + 11.20 + VAT + 160.00 + S + 7.00 + + + 63.84 + VAT + 336.00 + S + 19.00 + + + Zahlbar ohne Abzug bis zum 30.05.2017 + + 20170530 + + + + 496.00 + 0.00 + 0.00 + 496.00 + 75.04 + 571.04 + 571.04 + + + + +