diff --git a/History.md b/History.md index a7857771..05ce9552 100644 --- a/History.md +++ b/History.md @@ -7,6 +7,7 @@ - fluent setter api/pushprovider #40 - new xrechnung profile - visualization? zugferdvisualizer? +- migration feature (XSLT upgrade of ZF1 to ZF2) has been improved and moved from the commandline into the library - german bank account numbers can no longer be specified (dropped in favor of IBAN and BIC) - factory for xrechnung #86 - moved to Maven central @@ -17,7 +18,6 @@ - getSellerTradePartyAddress (PR #157 ) thanks to aberndt-hub - switched from eclipse to IntelliJ - added ph-schematron-maven-plugin so that xrechnung xslt can be generated -- removed migration feature (XSLT upgrade of ZF1) - be able to recursively validate directories - be able to ignore input pdf errors with -i - be able to recursively scan directories using validateExpectValid/validateExpectInvalid @@ -58,6 +58,9 @@ switch - *from A3 does not seem tow ork see mustangreaderwriteredgetest:testedgeexport - xmp errors may not show correctly in log - confirm correct generation from pdf/a3 files zf2edgetest +- visualization tests +- migration tests +- migration documentation - *correctiontest exports zf1+zf2? - *USt 0% wird aus invoice-klasse noch nicht sauber abgefangen - finalize invoiceimporter diff --git a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java index c7b16f32..987c8cc0 100755 --- a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java +++ b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java @@ -71,6 +71,10 @@ public class Main { + " [--profile <...>]: set ZUGFeRD profile\n" + " For ZUGFeRD v1: ASIC, OMFORT or EXENDED\n" + " For ZUGFeRD v2: INIMUM, BASIC L, ASIC, IUS, N16931, Rechnung, EXENDED " + + " upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n" + + " Additional parameters (optional - user will be prompted if not defined)\n" + + " [--source ]: set input XML ZUGFeRD 1 file\n" + + " [--out ]: set output XML ZUGFeRD 2 file\n" + " validate validate XML or PDF file \n" + " [--no-notices]: refrain from reporting notices\n" + " [--logAppend=]: text to be added to log line\n" @@ -221,8 +225,35 @@ public class Main { return selectedName; } + private static void performUpgrade(String xmlName, String outName) throws IOException, TransformerException { - // /opt/local/bin/mvn clean compile assembly:single + // Get params from user if not already defined + if (xmlName == null) { + xmlName = getFilenameFromUser("ZUGFeRD 1.0 XML source", "ZUGFeRD-invoice.xml", "xml", true, false); + } else { + 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); + } else { + System.out.println("ZUGFeRD 2 XML target to " + outName); + } + + // Verify params + ensureFileExists(xmlName); + ensureFileNotExists(outName); + + // All params are good! continue... + XMLUpgrader zmi = new XMLUpgrader(); + String xml = zmi.migrateFromV1ToV2(xmlName); + Files.write(Paths.get(outName), xml.getBytes()); + System.out.println("Written to " + outName); + + } + /*** + * the main function of the commandline tool... + * @param args + */ public static void main(String[] args) { try { @@ -303,6 +334,9 @@ public class Main { } else if ((action!=null)&&(action.equals("visualize"))) { performVisualization(sourceName, outName); optionsRecognized=true; + } else if ((action!=null)&&(action.equals("upgrade"))) { + performUpgrade(sourceName, outName); + optionsRecognized=true; } else if ((action!=null)&&(action.equals("validate"))) { optionsRecognized=performValidate(sourceName, noNotices!=null&&noNotices, parser.getOptionValue(logAppendOption)); } else if ((action!=null)&&(action.equals("validateExpectValid"))) { diff --git a/ZUGFeRD2-invoice.xml b/ZUGFeRD2-invoice.xml deleted file mode 100644 index 25d19521..00000000 --- a/ZUGFeRD2-invoice.xml +++ /dev/null @@ -1,205 +0,0 @@ - - - - - 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 - 44421800 - - - COBADEFFXXX - 41441604 - 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/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java index 2b8041ad..16ad9eb7 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IExportableTransaction.java @@ -30,6 +30,7 @@ package org.mustangproject.ZUGFeRD; import java.math.BigDecimal; import java.util.Date; +import org.mustangproject.FileAttachment; import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants; public interface IExportableTransaction { diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/XMLUpgrader.java b/library/src/main/java/org/mustangproject/ZUGFeRD/XMLUpgrader.java new file mode 100644 index 00000000..ff733e02 --- /dev/null +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/XMLUpgrader.java @@ -0,0 +1,68 @@ +package org.mustangproject.ZUGFeRD; + +import javax.xml.transform.*; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import java.io.*; + + +/*** + * Uses a XSLT transformation to upgrade + * from ZUGFeRD 1 to ZUGFeRD 2 (=Factur-X1 ˜= XRechnung) + * This is an external functionality of the software and not very complete, for + * internal operations (generation of ZF2) of course the ZF2PullProvider is used + */ +public class XMLUpgrader { + + static final ClassLoader CLASS_LOADER = XMLUpgrader.class.getClassLoader(); + private static final String RESOURCE_PATH = ""; //$NON-NLS-1$ + private TransformerFactory mFactory = null; + private Templates mXsltTemplate = null; + + public XMLUpgrader() { + mFactory = new net.sf.saxon.TransformerFactoryImpl(); + //fact = TransformerFactory.newInstance(); + mFactory.setURIResolver(new ClasspathResourceURIResolver()); + } + + /*** + * Takes a filename of a ZF1 XML file and returns the string of ZF2 XML + * @param xmlFilename + * @return String the updated XML + * @throws FileNotFoundException + * @throws TransformerException + * @throws UnsupportedEncodingException + */ + 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 + */ + mXsltTemplate = mFactory.newTemplates(new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZF1ToZF2.xsl"))); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + applySchematronXsl(new FileInputStream(xmlFilename), baos); + String res = null; + res = baos.toString("UTF-8"); + return res; + } + + protected 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/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 513ebf36..1e6f09c5 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -30,11 +30,13 @@ import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; +import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; 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.FileAttachment; import org.mustangproject.Invoice; import org.mustangproject.XMLTools; @@ -496,13 +498,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide // Additional Documents of XRechnung (Rechnungsbegruendende Unterlagen - BG-24 XRechnung) if (trans.getAdditionalReferencedDocuments() != null) { for (FileAttachment f : trans.getAdditionalReferencedDocuments()) { - final String documentContent = Base64.encodeBase64String(f.getData()); + // final String documentContent = Base64.encodeBase64String(f.getData()); xml = xml + " \n" + " " + f.getFilename() + "\n" + " 916\n" + " " + f.getDescription() + "\n" + " " + documentContent + "\n" +// + " filename=\"" + f.getFilename() + ">" + documentContent + "\n" + " \n"; } } diff --git a/library/src/main/resources/stylesheets/ZF1ToZF2.xsl b/library/src/main/resources/stylesheets/ZF1ToZF2.xsl new file mode 100644 index 00000000..e68c6552 --- /dev/null +++ b/library/src/main/resources/stylesheets/ZF1ToZF2.xsl @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +