diff --git a/History.md b/History.md index 704cc024..1a50736f 100644 --- a/History.md +++ b/History.md @@ -1,7 +1,7 @@ 1.7.2 ===== -2019-07-06 +2019-07-08 Support BuyerReference (r+w), as well as SpecifiedLegalOrganization (w) and DefinedTradeContact (w) use dom4j to format output xml document @@ -9,6 +9,7 @@ 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 diff --git a/pom.xml b/pom.xml index 67a0bb2a..ad1bfc0b 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,9 @@ - + 4.0.0 org.mustangproject.ZUGFeRD mustang - 1.7.2-SNAPSHOT + 1.7.3-SNAPSHOT jar Mustang The Mustang project is a java library to read and write ZUGFeRD meta data inside your invoice PDFs @@ -203,8 +202,7 @@ 2.4.3 - + org.mustangproject.toecount.Toecount diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 331e2a96..40ccc6eb 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -412,8 +412,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { + " \n" //$NON-NLS-1$ + " \n" //$NON-NLS-1$ + " " + payment.getOwnBIC() + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " " + payment.getOwnBLZ() //$NON-NLS-1$ - + "\n" //$NON-NLS-1$ // + " "+trans.getOwnBankName()+"\n" //$NON-NLS-1$ // //$NON-NLS-2$ + " \n" //$NON-NLS-1$ diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java index c9004873..a33ea2e3 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java @@ -128,8 +128,9 @@ public class ZUGFeRDImporter { private void extractFiles(Map names) throws IOException { for (String alias : names.keySet()) { - String filename=names.get(alias).getFilename(); - + + 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 @@ -137,7 +138,6 @@ public class ZUGFeRDImporter { 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); @@ -154,7 +154,6 @@ public class ZUGFeRDImporter { } if (filename.startsWith("additional_data")) { - PDComplexFileSpecification fileSpec = names.get(filename); PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile(); additionalXMLs.put(filename, embeddedFile.toByteArray()); 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..03b820b3 --- /dev/null +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -0,0 +1,134 @@ +/** ********************************************************************** + * + * 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.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; + + 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"))); + } 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 + */ + ByteArrayOutputStream iaos = new ByteArrayOutputStream(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + applySchematronXsl(new FileInputStream(xmlFilename), 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) { + // logging and exception handling should go here + } + 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 + e.printStackTrace(); + } + } + } + } + }).start(); + applySchematronXsl2(in, baos); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + 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 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/toecount/Toecount.java b/src/main/java/org/mustangproject/toecount/Toecount.java index 34b58526..f6f235a0 100755 --- a/src/main/java/org/mustangproject/toecount/Toecount.java +++ b/src/main/java/org/mustangproject/toecount/Toecount.java @@ -106,8 +106,7 @@ public class Toecount { + "\t\t[--source-xml ]: set input XML file\r\n" + "\t\t[--out ]: set output PDF file\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[--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"); } @@ -116,11 +115,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 = ""; @@ -159,15 +162,20 @@ 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 ensureFileNotExists will warn if file DOES exist (for output files) + * @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 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 { @@ -324,19 +332,62 @@ public class Toecount { performConvert(sourceName, outName); } else if (upgradeRequested) { performUpgrade(sourceName, outName); + } else if (action.equals("visualize")) { + performVisualization(sourceName, outName); } else { // no argument or argument unknown printUsage(); System.exit(2); } } catch (Exception e) { - + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); System.exit(-1); } } + private static void performVisualization(String sourceName, String outName) { + // Get params from user if not already defined + if (sourceName == null) { + sourceName = getFilenameFromUser("ZUGFeRD XML source", "zugferd-invoice.xml", "xml", true, false); + } else { + System.out.println("ZUGFeRD XML source set to " + sourceName); + } + if (outName == null) { + outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "factur-x.html", "html", false, true); + } else { + System.out.println("ZUGFeRD 1.0 XML source set to " + outName); + } + + // Verify params + try { + ensureFileExists(sourceName); + ensureFileNotExists(outName); + + // stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt + } catch (IOException e) { + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); + } + + ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer(); + String xml = null; + try { + xml = zvi.visualize(sourceName); + Files.write(Paths.get(outName), xml.getBytes()); + } catch (FileNotFoundException e) { + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); + } catch (UnsupportedEncodingException e) { + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); + } catch (TransformerException e) { + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); + } catch (IOException e) { + Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); + } + System.out.println("Written to " + outName); + + } + private static void performUpgrade(String xmlName, String outName) throws IOException, TransformerException { // Get params from user if not already defined @@ -426,7 +477,7 @@ public class Toecount { } private static void performCombine(String pdfName, String xmlName, String outName, String format, String zfVersion, - String zfProfile) throws Exception { + String zfProfile) throws Exception { /* * ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory() * .setProducer("toecount") .setCreator(System.getProperty("user.name")) @@ -464,7 +515,6 @@ public class Toecount { System.out.println("Format set to " + format); } - if (zfVersion == null) { try { zfVersion = getStringFromUser("Version (1 or 2)", "1", "1|2"); @@ -478,13 +528,12 @@ public class Toecount { if (zfProfile == null) { try { - if (format.equals("zf")&&(zfIntVersion == 1)) { - zfProfile = getStringFromUser("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( - "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) { Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e); @@ -499,12 +548,12 @@ public class Toecount { ensureFileExists(pdfName); ensureFileExists(xmlName); ensureFileNotExists(outName); - - if ((format.equals("fx"))&&(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 ((format.equals("zf")) && (zfIntVersion == 1)) { if (zfProfile.equals("b")) { zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASIC; } else if (zfProfile.equals("c")) { @@ -514,7 +563,7 @@ public class Toecount { } else { throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile)); } - } else if (((format.equals("zf"))&&(zfIntVersion == 2))||(format.equals("fx"))) { + } else if (((format.equals("zf")) && (zfIntVersion == 2)) || (format.equals("fx"))) { if (zfProfile.equals("m")) { zfConformanceLevelProfile = ZUGFeRDConformanceLevel.MINIMUM; } else if (zfProfile.equals("w")) { @@ -543,7 +592,6 @@ public class Toecount { if (format.equals("fx")) { ze.setFacturX(); } - ze.setZUGFeRDXMLData(Files.readAllBytes(Paths.get(xmlName))); diff --git a/src/main/resources/stylesheets/cii-xr.xsl b/src/main/resources/stylesheets/cii-xr.xsl new file mode 100644 index 00000000..5fca7b9d --- /dev/null +++ b/src/main/resources/stylesheets/cii-xr.xsl @@ -0,0 +1,2202 @@ + + + + + + Author: KoSIT Bremen (kosit@finanzen.bremen.de) + Fassung vom: 2019-03-18+01:00 + Überführt eine zur EN 16931 konforme elektronische Rechnung in der konkreten Syntax UNCEFACT.CII.D16B in eine Instanz gemäß des Schemas für den Namensraum urn:ce.eu:en16931:2017:xoev-de:kosit:standard:xrechnung-1. + Das Skript setzt voraus, dass das zu verarbeitende Dokument valide bzgl. des XML Schemas und der Schematron-Regeln der Quelle ist. Für nicht valide Dokumente ist das Ergebnis nicht definiert. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ILLEGAL DATE FORMAT: <para>Mit diesem Datentyp wird ein kalendarisches Datum abgebildet, wie es in der ISO 8601 Spezifikation <quote>Calendar date complete representation</quote> beschrieben ist (siehe ISO 8601:2004, Abschnitt 5.2.1.1). Das Datum beinhaltet keine Zeitangabe. Das konkret zu verwendende Format ist abhängig von der genutzten Syntax.</para> +<para>Der Datentyp basiert auf dem Typ <quote>Date Time. Type</quote>, wie in ISO 15000-5:2014 Anhang B definiert.</para> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Liefert einen XPath-Pfad, welches $n eindeutig identifiziert. + + + + + + + + + + + Liefert einen XPath-Pfad, welches $n eindeutig identifiziert. + + + + + / + + + [ + + ] + + + + /@ + + + diff --git a/src/main/resources/stylesheets/xrechnung-html.xsl b/src/main/resources/stylesheets/xrechnung-html.xsl new file mode 100644 index 00000000..5e15f314 --- /dev/null +++ b/src/main/resources/stylesheets/xrechnung-html.xsl @@ -0,0 +1,1188 @@ + + + + + + + + + + + + + + + XRechnung + + + + +
+ +
+
+
+ + + + + +
+
+ + + +
+ + + +
+
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
+
+
+ + + +
+ + + +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+
+
+ + + +
+
Informationen zum Käufer
+
+
+
Leitweg-ID:
+
+
+
+
Name:
+
+
+
+
Straße / Hausnummer:
+
+
+
+
Postfach:
+
+
+
+
Adresszusatz:
+
+
+
+
PLZ:
+
+
+
+
Ort:
+
+
+
+
Land:
+
+
+
+
Kennung:
+
+
+
+
Schema der Kennung:
+
+
+
+
Name:
+
+
+
+
Telefon:
+
+
+
+
E-Mail-Adresse:
+
+
+
+
+
+ + + +
+
Informationen zum Verkäufer
+
+
+
Firmenname:
+
+
+
+
Straße / Hausnummer:
+
+
+
+
Postfach:
+
+
+
+
Adresszusatz:
+
+
+
+
PLZ:
+
+
+
+
Ort:
+
+
+
+
Bundesland:
+
+
+
+
Ländercode:
+
+
+
+
Kennung:
+
+
+
+
Schema der Kennung:
+
+
+
+
Name:
+
+
+
+
Telefon:
+
+
+
+
E-Mail-Adresse:
+
+
+
+
+
+ + + +
+
+
Rechnungsdaten
+
+
+
+
+
Rechnungsnummer:
+
+
+
+
Rechnungsdatum:
+
+
+
+
Rechnungsart:
+
+
+
+
Währung:
+
+
+
+

Abrechnungszeitraum:

+
+
+
von:
+
+
+
+
bis:
+
+
+
+
+
+
+
+
+
Projektnummer:
+
+
+
+
Vertragsnummer:
+
+
+
+
Bestellnummer:
+
+
+
+
Auftragsnummer:
+
+
+
+

Vorausgegangene Rechnungen:

+ +
+
+
+
+
+ + +
+
+
Rechnungsnummer:
+
+
+
+
Rechnungsdatum:
+
+
+
+
+ + + +
+
+
Gesamtbeträge der Rechnung
+
+
+
Summe aller Positionen
+
netto
+
+
+
+
Summe Nachlässe
+
netto
+
+
+
+
Summe Zuschläge
+
netto
+
+
+
+
Gesamtsumme
+
netto
+
+
+
+
Summe Umsatzsteuer
+
+
+
+
+
Summe Umsatzsteuer in Abrechnungswährung
+
+
+
+
+
Gesamtsumme
+
brutto
+
+
+
+
Gezahlter Betrag
+
brutto
+
+
+
+
Rundungsbetrag
+
brutto
+
+
+
+
Fälliger Betrag
+
brutto
+
+
+
+
+
+
+ + + +
+
+
Aufschlüsselung der Umsatzsteuer auf Ebene der Rechnung
+
+
+
Umsatzsteuerkategorie:
+
+
+
+
+
Gesamtsumme
+
netto
+
+
+
+
Umsatzsteuersatz
+
+
%
+
+
+
Umsatzsteuerbetrag
+
+
+
+
+ +
+
Befreiungsgrund:
+
Kennung für den Befreiungsgrund:
+
+
+
+
+ + + +
+
+
Nachlass auf Ebene der Rechnung
+
+
+
Umsatzsteuerkategorie des Nachlasses:
+
+
+
+
+
Grundbetrag
+
netto
+
+
+
+
Prozentsatz
+
+
%
+
+
+
Nachlass
+
netto
+
+
+
+
Umsatzsteuersatz des Nachlasses
+
+
+
+
+
+
Grund für den Nachlass:
+
Document level allowance reason code:
+
+
+
+
+
+ + + +
+
+
Zuschlag auf Ebene der Rechnung
+
+
+
Umsatzsteuerkategorie des Zuschlages:
+
+
+
+
+
Grundbetrag
+
netto
+
+
+
+
Prozentsatz
+
+
%
+
+
+
Zuschlag
+
netto
+
+
+
+
Umsatzsteuersatz des Zuschlages
+
+
+
+
+
+
Grund für den Zuschlag:
+
Document level charge reason code:
+
+
+
+
+
+ + + +
+
Zahlungsdaten
+
+
+
Skonto; weitere Zahlungsbedingungen:
+
+
+
+
Fälligkeitsdatum:
+
+
+
+
Code für das Zahlungsmittel:
+
+
+
+
Zahlungsmittel:
+
+
+
+
Verwendungszweck:
+
+
+
+
+
+ + + +
+
Karteninformation
+
+
+
Kartennummer:
+
+
+
+
Karteninhaber:
+
+
+
+
+
+ + + +
+
Lastschrift
+
+
+
Mandatsreferenznr.:
+
+
+
+
IBAN:
+
+
+
+
Gläubiger-ID:
+
+
+
+
+
+ + + +
+
Überweisung
+
+
+
Kontoinhaber:
+
+
+
+
IBAN:
+
+
+
+
BIC:
+
+
+
+
+
+ + + +
+
Bemerkung zur Rechnung
+
+
+
Betreff:
+
+
+
+
Bemerkung:
+
+
+
+
+
+ + + +
+
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
+ +
+
+ + + +
+
+
+
Position
+
+
+
Freitext:
+
+
+
+
Objektkennung:
+
+
+
+
Schema der Objektkennung:
+
+
+
+
Nummer der Auftragsposition:
+
+
+
+
Kontierungshinweis:
+
+
+

Abrechnungszeitraum:

+
+
von:
+
+
+
+
bis:
+
+
+
+
+
+
Preiseinzelheiten
+
+
+
Menge
+
+
+
+
Einheit
+
+
+
+
Preis pro Einheit (netto)
+
+
+
+
Gesamtpreis (netto)
+
+
+
+
+
+
Rabatt (netto):
+
+
+
+
Listenpreis (netto):
+
+
+
+
Anzahl der Einheit:
+
+
+
+
Code der Maßeinheit:
+
+
+
+
Umsatzsteuer:
+
+
+
+
Umsatzsteuersatz in Prozent:
+
%
+
+
+
+
+
+
+
+
+
Nachlässe auf Ebene der Rechnungsposition
+
+
+
Grundbetrag (netto)
+
+
+
+
Prozentsatz
+
%
+
+
+
Nachlass (netto)
+
+
+
+
+
Grund des Nachlasses:
+
Code für den Nachlassgrund:
+
+
+
+
Zuschläge auf Ebene der Rechnungsposition
+
+
+
Grundbetrag (netto)
+
+
+
+
Prozentsatz
+
%
+
+
+
Zuschlag (netto)
+
+
+
+
+
Grund des Zuschlags:
+
Code für den Zuschlagsgrund:
+
+
+
+
+
+
+
+
Artikelinformationen
+
+
+
+
+
+
Bezeichnung:
+
+
+
+
Beschreibung:
+
+
+
+
Artikelnummer:
+
+
+
+
Artikelkennung des Käufers:
+
+
+

Eigenschaften des Artikels:

+ +
+
+
+
+
+
+
Artikelkennung:
+
+
+
+
Schema der Artikelkennung:
+
+
+
+
Code der Artikelklassifizierung:
+
+
+
+
Kennung zur Bildung des Schemas:
+
+
+
+
Version zur Bildung des Schemas:
+
+
+
+
Code des Herkunftslandes:
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+ + + +
+
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+ + + +
+
Informationen zum Verkäufer
+
+
+
Abweichender Handelsname:
+
+
+
+
Bundesland:
+
+
+
+
Elektronische Adresse:
+
+
+
+
Schema der elektronischen Adresse:
+
+
+
+
Register-/Registriernummer:
+
+
+
+
Umsatzsteuer-ID:
+
+
+
+
Steuernummer:
+
+
+
+
Schema der Steuernummer:
+
+
+
+
Weitere rechtliche Informationen:
+
+
+
+
Code der Umsatzsteuerwährung:
+
+
+
+
+
+ + + +
+
Steuervertreter des Verkäufers
+
+
+
Name:
+
+
+
+
Straße / Hausnummer:
+
+
+
+
Postfach:
+
+
+
+
Adresszusatz:
+
+
+
+
PLZ:
+
+
+
+
Ort:
+
+
+
+
Bundesland:
+
+
+
+
Ländercode:
+
+
+
+
Umsatzsteuer-ID:
+
+
+
+
+
+ + + +
+
Informationen zum Käufer
+
+
+
Abweichender Handelsname:
+
+
+
+
Bundesland:
+
+
+
+
Elektronische Adresse:
+
+
+
+
Schema der elektronischen Adresse:
+
+
+
+
Register-/Registriernummer:
+
+
+
+
Schema der Register-/Registriernummer:
+
+
+
+
Umsatzsteuer-ID:
+
+
+
+
Abrechnungsdatum der Umsatzsteuer:
+
+
+
+
Code des Umsatzsteuer-Abrechnungsdatums:
+
+
+
+
Kontierungsinformation:
+
+
+
+
+
+ + + +
+
Lieferinformationen
+
+
+
Kennung des Lieferorts:
+
+
+
+
Schema der Kennung:
+
+
+
+
Lieferdatum:
+
+
+
+
Name des Empfängers:
+
+
+
+
Straße / Hausnummer:
+
+
+
+
Postfach:
+
+
+
+
Adresszusatz:
+
+
+
+
PLZ:
+
+
+
+
Ort:
+
+
+
+
Bundesland:
+
+
+
+
Land:
+
+
+
+
+
+ + + +
+
Informationen zum Vertrag
+
+
+
Vergabenummer:
+
+
+
+
Kennung der Empfangsbestätigung:
+
+
+
+
Kennung der Versandanzeige:
+
+
+
+
Prozesskennung:
+
+
+
+
Spezifikationskennung:
+
+
+
+
Objektkennung:
+
+
+
+
Schema der Objektkennung:
+
+
+
+
+
+ + + +
+
Vom Verkäufer abweichender Zahlungsempfänger
+
+
+
Name:
+
+
+
+
Kennung:
+
+
+
+
Schema der Kennung:
+
+
+
+
Register-/Registriernummer:
+
+
+
+
Schema der Register-/Registriernummer:
+
+
+
+
+
+ + + +
+
Wir übernehmen keine Haftung für die Richtigkeit der Daten.
+
+
+
+
Rechnungsbegründende Unterlagen
+ +
+
+
+
+
+ + + +
+
+
Kennung:
+
+
+
+
Beschreibung:
+
+
+
+
Verweis (z.B. Internetadresse):
+
+
+
+
Anhangsdokument:
+
+ Öffnen +
+ + +
+
+
Format des Anhangdokuments:
+
+
+
+
Name des Anhangsdokuments:
+
+
+
+
+ + + +
+
+
+
+
Bearbeitungshistorie
+ +
+
+
+
+
+ + + +
+
+
Datum/Uhrzeit:
+
+
+
+
Betreff:
+
+
+
+
Text:
+
+
+
+
Details:
+
+
+
+
+ +
diff --git a/xrechnung-viewer.css b/xrechnung-viewer.css new file mode 100644 index 00000000..adea4c9b --- /dev/null +++ b/xrechnung-viewer.css @@ -0,0 +1,917 @@ +/* Grundformatierung ********************************************/ + +*, +*:after, +*:before +{ + box-sizing: border-box; + -moz-box-sizing: border-box; +} + +.clear:after +{ + content: "."; + clear: both; + display: block; + visibility: hidden; + height: 0; +} + +html, +body +{ + height: 100%; + min-width: 320px; + margin: 0; + padding: 0; + color: #000; + font-size: 14px; +} + +body +{ + overflow-y: scroll; + background-color: rgba(4, 101, 161, 0.08); +} + +h4 +{ + color: inherit; + font-size: inherit; + margin-bottom: 0.5rem; +} + + +/* Grundaufbau *************************************************/ + +.menue +{ + position: relative; + z-index: 2000; + background-color: #000; + margin-bottom: 30px; +} + +.innen +{ + max-width: 1080px; + margin: 0 auto; + padding: 0 2%; +} + + + +/* Formatierungen *************************************************/ + +.color2 +{ + color: rgba(0, 0, 0, 0.6); +} + +.schwarz +{ + color: #555 !important; +} + +.normal +{ + font-weight: normal; +} + +.bold +{ + font-weight: bold; +} + +.abstandUnten +{ + margin-bottom: 5px; +} + +.abstandUntenKlein +{ + margin-bottom: 10px; +} + +.noPaddingTop +{ + padding-top: 0 !important; +} + +.ausrichtungRechts +{ + text-align: right; +} + + + + +/* Menü ********************************************************/ + +button +{ + position: relative; + font-family: serif; + padding-top: 15px; + padding-left: 0; + padding-right: 0; + margin-right: 2%; +} + +.btnAktiv +{ + font-size: 22px; + color: #ffb619; + height: 50px; + outline: none; + border: none; + background: none; +} + +.btnAktiv:after +{ + content: ""; + display: block; + position: absolute; + top: 50px; + left: 50%; + z-index: 10; + font-size: 0; + line-height: 0; + height: 0; + padding: 0; + margin: 0; + transform: translateX(-50%); + border: 15px solid #000; + border-right-color: transparent; + border-bottom-color: transparent; + border-left-color: transparent; +} + +.btnInaktiv, +.tab +{ + font-size: 22px; + color: #fff; + height: 50px; + z-index: 0; + outline: none; + border: none; + background: none; + transition: color 0.3s ease; +} + +.btnInaktiv:hover, +.tab:hover +{ + color: #ffb619; + cursor: pointer; +} + +.divHide +{ + display: none; +} + +/* Content *********************************************************************/ + +.inhalt +{ + font-family: sans-serif; + margin-bottom: 30px; +} + +.haftungausschluss +{ + color: #000; + text-align: center; + padding: 7px; + margin-bottom: 30px; + width: 100%; + border: 1px solid #ffb619; + background-color: #fff; +} + +.box +{ + position: relative; + display: table-cell; + padding: 0; + border: 1px solid rgba(4, 101, 161, 0.2); + background-color: #fff; +} + +.subBox +{ + border-top: none; + width: 50%; +} + +.subBox:last-child +{ + border-left: none; +} + +.first > .boxzeile > .subBox +{ + border-top: 1px solid rgba(4, 101, 161, 0.2) !important; +} + +.boxtitel +{ + display: inline-block; + background-color: #0465A1; + padding: 7px 10px; + color: #fff; + font-weight: bold; +} + +.boxBorderTop +{ + border-top: none; +} + +.boxBorderLeft +{ + border-left: none; +} + +.boxtitelSub +{ + color: #000; + background-color: rgba(4, 101, 161, 0.1); + border-right: 1px solid rgba(4, 101, 161, 0.2); + border-bottom: 1px solid rgba(4, 101, 161, 0.2); +} + +.boxinhalt +{ + padding: 15px 20px; +} + +.boxtabelle +{ + display: table; + width: 100%; +} + +.borderSpacing +{ + border-spacing: 0 5px; +} + +.boxabstandtop +{ + margin-top: 30px; +} + +.boxzeile +{ + display: table-row; +} + +.boxzeile .box:last-child +{ + margin-bottom: 0; +} + +.boxdaten +{ + display: table-cell; + padding: 5px 0; + vertical-align: middle; + height: 38px; + /* + -ms-word-break: break-all; + word-break: break-all; + word-break: break-word; + -webkit-hyphens: auto; + -moz-hyphens: auto; + hyphens: auto; +*/ +} + +.boxdaten.wert +{ + padding: 5px 10px; +} + +.boxcell +{ + display: table-cell; +} + +.boxdatenBlock +{ + display: block; + padding: 3px 0; + /* + -ms-word-break: break-all; + word-break: break-all; + word-break: break-word; + -webkit-hyphens: auto; + -moz-hyphens: auto; + hyphens: auto; +*/ +} + +.noBreak +{ + -ms-word-break: keep-all; + word-break: keep-all; + word-break: keep-all; + -webkit-hyphens: none; + -moz-hyphens: none; + hyphens: none; +} + +.boxabstand +{ + display: table-cell; + width: 30px; +} + +.legende +{ + color: rgba(0, 0, 0, 0.6); + width: 170px; + font-size: 13px; + line-height: 16px; + padding-right: 5px; +} + +.wert +{ + background-color: rgba(4, 101, 161, 0.03); +} + +.boxtabelleEinspaltig +{ + width: 49%; +} + +.boxtabelleZweispaltig, +.boxtabelleDreispaltig +{ + width: 100%; +} + +.box5050 +{ + width: 50%; +} + +.boxEinspaltig +{ + width: 100%; +} + +.boxZweispaltig +{ + width: 48.5%; +} + +.boxSpalte1 { + width: 50%; +} + +.boxSpalte2 { + width: 50%; + padding-left: 20px; +} + +.paddingLeft { + padding-left: 0.1em; +} + +.noPadding { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.rechnungsZeile +{ + display: table-row; +} + +.rechnungsZeile .boxdaten +{ + height: auto; +} + +.rechnungSp1 +{ + width: 65%; + font-size: 16px; +} + +.rechnungSp2 +{ + width: 10%; +} + +.rechnungSp3 +{ + width: 25%; + font-size: 16px; + text-align: right; +} + +.detailSp1, +.detailSp2 +{ + width: 50%; +} + +.detailSp2 +{ + text-align: right; +} + +.line1Bottom +{ + border-bottom: 1px solid #000; +} + +.line1BottomLight +{ + padding-bottom: 5px; + border-bottom: 1px solid #f0f0f0; + margin-bottom: 5px; +} + +.line2Bottom +{ + border-bottom: 2px solid #000; +} + +.paddingTop +{ + padding-top: 10px; +} + +.paddingBottom +{ + padding-bottom: 10px; +} + +.grund +{ + font-size: 16px; + display: block; + width: 100%; + padding: 0 20px 15px 20px; +} + +.grundDetail +{ + display: block; + width: 100%; + padding: 0 20px 15px 20px; +} + +/* Übersichtformatierungen */ +#uebersichtLastschrift.box, +#uebersichtUeberweisung.box +{ + border-top: none; +} + +#uebersichtUeberweisung.box +{ + border-left: none; +} + + +/* Formatierungen Detailseite */ + +.detailsSpalte1, +.detailsSpalte2 +{ + width: 30%; + float: left; + font-size: 90%; + line-height: 115%; + margin-right: 5%; +} + +.detailsSpalte3 +{ + width: 30%; + float: left; + font-size: 90%; + line-height: 115%; +} + +.detailsSpalte1 .legende, +.detailsSpalte2 .legende, +.detailsSpalte3 .legende +{ + width: 145px; +} + +.titelPosition +{ + font-size: 17px; + font-weight: bold; +} + + +/* Laufzettelformatierungen */ +#laufzettelHistorie .boxtabelle:not(:nth-child(2)) +{ + border-top: 1px solid rgba(4, 101, 161, 0.2); + padding-top: 10px; + margin-top: 10px; +} + + + + + +/* 1023px und kleiner ************************************************/ + +@media screen and (max-width : 1023px) { + + .box + { + display: block; + width: 100%; + margin-bottom: 20px; + } + + .boxabstandtop + { + margin-top: 15px; + } + + .subBox:first-child + { + margin-bottom: 0 !important; + } + + .subBox:last-child + { + border-left: 1px solid rgba(4, 101, 161, 0.2); + } + + .first > .boxzeile > .subBox + { + border-top: none !important; + } + + .first > .boxzeile > .subBox:first-child + { + border-top: 1px solid rgba(4, 101, 161, 0.2) !important; + } + + .first > .boxzeile + { + margin-bottom: 0; + } + + #uebersichtUeberweisung.box + { + border-left: 1px solid rgba(4, 101, 161, 0.2); + } + + #uebersichtLastschrift.box + { + margin-bottom: 0; + } + + .boxzeile + { + display: block; + margin-bottom: 5px; + } + + .boxzeile:after + { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; + } + + #details > .boxtabelle > .boxzeile + { + margin-bottom: 0px; + } + + .boxcell + { + display: block; + } + + .boxcell:last-child + { + margin-top: 20px; + } + + .boxZweispaltig + { + width: 100%; + } + + .legende + { + display: block; + float: left; + width: 170px; + padding: 5px 0; + height: auto; + } + + .wert + { + display: block; + float: left; + width: calc(100% - 170px); + padding: 11px 10px !important; + line-height: 1.3; + min-height: 38px; + height: auto; + } + + .boxdaten .legende + { + height: auto; + } + + .rechnungsZeile .boxdaten + { + padding: 5px 0; + } + + .boxabstand + { + display: none; + } + + .boxtabelleEinspaltig { + width: 100%; + } + + .boxSpalte1 { + display: block; + width: auto; + } + + .boxSpalte2 { + display: block; + width: auto; + padding-left: 0px; + margin-top: 1.2rem; + } + + .detailsSpalte1, + .detailsSpalte2, + .detailsSpalte3 + { + width: 100%; + float: none; + padding-right: 0px; + } + + .detailsSpalte2, + .detailsSpalte3 + { + margin-top: 15px; + } + + .detailsSpalte2, + .detailsSpalte3 + { + margin-top: 10px; + } + + .tableNumberAlignRight + { + display: block; + width: 130px; + text-align: right; + } +} + + + +/* 800px und kleiner ************************************************/ + +@media screen and (max-width : 800px) { + + button + { + padding-top: 10px; + } + + .btnAktiv, + .btnInaktiv, + .tab + { + font-size: 20px; + height: 40px; + } + + .btnAktiv:after + { + top: 40px; + } + + .rechnungSp1 + { + width: 55%; + font-size: 15px; + } + + .rechnungSp2 + { + width: 10%; + } + + .rechnungSp3 + { + width: 35%; + text-align: right; + font-size: 15px; + } + + .grund + { + font-size: 15px; + } +} + +/* 450px und kleiner ************************************************/ + +@media screen and (max-width : 450px) +{ + + html, + body + { + font-size: 12px; + } + + .menue + { + margin-bottom: 20px; + } + + button + { + padding-top: 5px; + } + + .btnAktiv, + .btnInaktiv, + .tab + { + font-size: 17px; + height: 35px; + } + + .btnAktiv:after + { + top: 35px; + } + + .legende + { + font-size: 12px; + width: 100%; + } + + .wert + { + font-size: 12px; + line-height: 1.3; + width: 100%; + margin-bottom: 10px + } + + .boxzeile + { + margin-bottom: 0px + } + + .boxdaten + { + height: auto; + } + + .haftungausschluss + { + margin-bottom: 20px; + } + + .boxinhalt + { + margin-top: 0px; + } + + .boxabstandtop + { + margin-top: 20px; + } + + .boxtitel + { + padding: 7px 8px; + } + + .box + { + margin-bottom: 10px; + padding: 0; + } + + .boxabstandtop + { + margin-top: 10px; + } + + .boxdaten, + .boxdatenBlock + { + padding: 2px 0; + } + + .rechnungSp1 + { + width: 50%; + font-size: inherit; + } + + .rechnungSp2 + { + width: 15%; + } + + .rechnungSp3 + { + width: 35%; + font-size: inherit; + text-align: right; + } + + .grund + { + font-size: inherit; + } + + .titelPosition + { + font-size: 15px; + } + + .abstandUnten + { + margin-bottom: 5px; + } + + .detailsSpalte1, + .detailsSpalte2, + .detailsSpalte3 + { + font-size: inherit; + line-height: inherit; + } +} + +/* 380px und kleiner ************************************************/ + +@media screen and (max-width : 380px) { + + html, + body + { + font-size: 11px; + line-height: 100%; + } + + .btnAktiv, + .btnInaktiv, + .tab + { + font-size: 15px; + } + + .boxdaten +.boxdatenBlock + { + padding: 2px 0; + } + + .boxinhalt + { + margin-top: 0px; + } + + .boxtitel + { + padding: 5px 7px; + } +} diff --git a/xrechnung-viewer.js b/xrechnung-viewer.js new file mode 100644 index 00000000..2d547b86 --- /dev/null +++ b/xrechnung-viewer.js @@ -0,0 +1,145 @@ + +/* Tab-Container aufbauen **************************************************/ + +var a = new Array("uebersicht", "details", "zusaetze", "anlagen", "laufzettel"); +var b = new Array("menueUebersicht", "menueDetails", "menueZusaetze", "menueAnlagen", "menueLaufzettel"); + +function show(e) { + var i = 0; + var j = 1; + for (var t = 0; t < b.length; t++) { + if (b[t] === e.id) { + i = t; + if (i > 0) { + j = 0; + } else { + j = i + 1; + } + break; + } + } + e.setAttribute("class", "btnAktiv"); + for (var k = 0; k < b.length; k++) { + if (k === i && (document.getElementById(a[k]) != null)) { + document.getElementById(a[k]).style.display = "block"; + if (i === j) + j = i + 1; + } else { + if (document.getElementById(a[k]) != null) { + document.getElementById(a[j]).style.display = "none"; + document.getElementById(b[j]).setAttribute("class", "btnInaktiv"); + j += 1; + } + } + } +} +window.onload = function () { + document.getElementById(b[0]).setAttribute("class", "btnAktiv"); +} + +/* Eingebettete Binaerdaten runterladen ************************************/ + + +function base64_to_binary (data) { + var chars = atob(data); + var bytes = new Array(chars.length); + for (var i = 0; i < chars.length; i++) { + bytes[i] = chars.charCodeAt(i); + } + return new Uint8Array(bytes); +} + +function downloadData (element_id) { + var data_element = document.getElementById(element_id); + var mimetype = data_element.getAttribute('mimeType'); + var filename = data_element.getAttribute('filename'); + var text = data_element.innerHTML; + var binary = base64_to_binary(text); + var blob = new Blob([binary], { + type: mimetype, size: binary.length + }); + + if (window.navigator && window.navigator.msSaveOrOpenBlob) { + // IE + window.navigator.msSaveOrOpenBlob(blob, filename); + } else { + // Non-IE + var url = window.URL.createObjectURL(blob); + window.open(url); + } +} + + +/* Polyfill IE atob/btoa ************************************/ + +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], function () { + factory(root); + }); + } else factory(root); + // node.js has always supported base64 conversions, while browsers that support + // web workers support base64 too, but you may never know. +})(typeof exports !== "undefined" ? exports: this, function (root) { + if (root.atob) { + // Some browsers' implementation of atob doesn't support whitespaces + // in the encoded string (notably, IE). This wraps the native atob + // in a function that strips the whitespaces. + // The original function can be retrieved in atob.original + try { + root.atob(" "); + } + catch (e) { + root.atob = (function (atob) { + var func = function (string) { + return atob(String(string).replace(/[\t\n\f\r ]+/g, "")); + }; + func.original = atob; + return func; + })(root.atob); + } + return; + } + + // base64 character set, plus padding character (=) + var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + // Regular expression to check formal correctness of base64 encoded strings + b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/; + + root.btoa = function (string) { + string = String(string); + var bitmap, a, b, c, + result = "", i = 0, + rest = string.length % 3; // To determine the final padding + + for (; i < string.length;) { + if ((a = string.charCodeAt(i++)) > 255 || (b = string.charCodeAt(i++)) > 255 || (c = string.charCodeAt(i++)) > 255) + throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range."); + + bitmap = (a << 16) | (b << 8) | c; + result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63) + b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63); + } + + // If there's need of padding, replace the last 'A's with equal signs + return rest ? result.slice(0, rest - 3) + "===".substring(rest): result; + }; + + root.atob = function (string) { + // atob can work with strings with whitespaces, even inside the encoded part, + // but only \t, \n, \f, \r and ' ', which can be stripped. + string = String(string).replace(/[\t\n\f\r ]+/g, ""); + if (! b64re.test(string)) + throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded."); + + // Adding the padding if missing, for semplicity + string += "==".slice(2 - (string.length & 3)); + var bitmap, result = "", r1, r2, i = 0; + for (; i < string.length;) { + bitmap = b64.indexOf(string.charAt(i++)) << 18 | b64.indexOf(string.charAt(i++)) << 12 | (r1 = b64.indexOf(string.charAt(i++))) << 6 | (r2 = b64.indexOf(string.charAt(i++))); + + result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255): r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255): String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255); + } + return result; + }; +}); \ No newline at end of file