Merge pull request #1083 from truearken/feature-pdf-langs

PDF Visualizations in English and French
This commit is contained in:
Jochen Staerk
2026-04-09 11:22:16 +02:00
committed by GitHub
5 changed files with 633 additions and 315 deletions

View File

@@ -44,74 +44,73 @@ public class Main {
private static String getUsage() { private static String getUsage() {
return "Usage: --action metrics|combine|extract|a3only|ubl|validate|validateExpectInvalid|validateExpectValid|visualize [-d,--directory] [-l,--listfromstdin] [-i,--ignore fileextension, PDF/A errors] [--disable-file-logging] | [-h,--help] \r\n" return "Usage: --action metrics|combine|extract|a3only|ubl|validate|validateExpectInvalid|validateExpectValid|visualize [-d,--directory] [-l,--listfromstdin] [-i,--ignore fileextension, PDF/A errors] [--disable-file-logging] | [-h,--help] \r\n"
+ " --action license display open source license and notice\n" + " --action license display open source license and notice\n"
+ " --action metrics\n" + " --action metrics\n"
+ " -d, --directory count ZUGFeRD files in directory to be scanned\n" + " -d, --directory count ZUGFeRD files in directory to be scanned\n"
+ " If it is a directory, it will recurse.\n" + " If it is a directory, it will recurse.\n"
+ " -l, --listfromstdin count ZUGFeRD files from a list of linefeed separated files on runtime.\n" + " -l, --listfromstdin count ZUGFeRD files from a list of linefeed separated files on runtime.\n"
+ " It will start once a blank line has been entered.\n" + "\n" + " It will start once a blank line has been entered.\n" + "\n"
+ " Additional parameter for both count operations\n" + " Additional parameter for both count operations\n"
+ " [-i, --ignorefileextension] Check for all files (*.*) instead of PDF files only (*.pdf) in metrics, ignore PDF/A input file errors in combine\n" + " [-i, --ignorefileextension] Check for all files (*.*) instead of PDF files only (*.pdf) in metrics, ignore PDF/A input file errors in combine\n"
+ " [--disable-file-logging] disable logging to file.\n" + " [--disable-file-logging] disable logging to file.\n"
+ " --action extract extract Factur-X PDF to XML file\n" + " --action extract extract Factur-X PDF to XML file\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n" + " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n" + " [--source <filename>]: set input PDF file\n"
+ " [--out <filename>]: set output XML file\n" + " [--out <filename>]: set output XML file\n"
+ " --action a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n" + " --action a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n" + " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n" + " [--source <filename>]: set input PDF file\n"
+ " [--out <filename>]: set output PDF file\n" + " [--out <filename>]: set output PDF file\n"
+ " --action combine combine XML and PDF file to Factur-X PDF file\n" + " --action combine combine XML and PDF file to Factur-X PDF file\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n" + " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input PDF file\n" + " [--source <filename>]: set input PDF file\n"
+ " [--source-xml <filename>]: set input XML file\n" + " [--source-xml <filename>]: set input XML file\n"
+ " [--out <filename>]: set output PDF file\n" + " [--out <filename>]: set output PDF file\n"
+ " [--format <fx|zf|ox|da>]: set Factur-X, ZUGFeRD, Order-X or Cross Industry Despatch Advice\n" + " [--format <fx|zf|ox|da>]: set Factur-X, ZUGFeRD, Order-X or Cross Industry Despatch Advice\n"
+ " [--version <1|2>]: set ZUGFeRD version\n" + " [--version <1|2>]: set ZUGFeRD version\n"
+ " [--profile <...>]: set ZUGFeRD profile\n" + " [--profile <...>]: set ZUGFeRD profile\n"
+ " For ZUGFeRD v1 or Order-X: <B>ASIC, <C>OMFORT or EX<T>ENDED\n" + " For ZUGFeRD v1 or Order-X: <B>ASIC, <C>OMFORT or EX<T>ENDED\n"
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, <X>Rechnung, EX<T>ENDED\n" + " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, <X>Rechnung, EX<T>ENDED\n"
+ " [--attachments <filenames>]: list of file attachments (passing a single empty file name prevents prompting)\n" + " [--attachments <filenames>]: list of file attachments (passing a single empty file name prevents prompting)\n"
+ " [--no-additional-attachments]: prevent prompting for attachments\n" + " [--no-additional-attachments]: prevent prompting for attachments\n"
+ " --action ubl convert UN/CEFACT 2016b CII XML to UBL XML\n" + " --action ubl convert UN/CEFACT 2016b CII XML to UBL XML\n"
+ " [--source <filename>]: set input XML file\n" + " [--source <filename>]: set input XML file\n"
+ " [--out <filename>]: set output XML file\n" + " [--out <filename>]: set output XML file\n"
+ " --action upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n" + " --action upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n" + " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: set input XML ZUGFeRD 1 file\n" + " [--source <filename>]: set input XML ZUGFeRD 1 file\n"
+ " [--out <filename>]: set output XML ZUGFeRD 2 file\n" + " [--out <filename>]: set output XML ZUGFeRD 2 file\n"
+ " --action validate validate XML or PDF file \n" + " --action validate validate XML or PDF file \n"
+ " [--no-notices]: refrain from reporting notices\n" + " [--no-notices]: refrain from reporting notices\n"
+ " [--logAppend <text>]: text to be added to log line\n" + " [--logAppend <text>]: text to be added to log line\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n" + " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: input PDF or XML file\n" + " [--source <filename>]: input PDF or XML file\n"
+ " [--log-as-pdf]: save log output as pdf\n" + " [--log-as-pdf]: save log output as pdf\n"
+ " --action validateExpectInvalid validate directory recursively expecting negative results \n" + " --action validateExpectInvalid validate directory recursively expecting negative results \n"
+ " [--no-notices]: refrain from reporting notices\n" + " [--no-notices]: refrain from reporting notices\n"
+ " Additional parameters (user will be prompted if not defined)\n" + " Additional parameters (user will be prompted if not defined)\n"
+ " -d, --directory to check recursively\n" + " -d, --directory to check recursively\n"
+ " Additional parameters (optional)\n" + " Additional parameters (optional)\n"
+ " --exclude: comma-separated list of filenames to ignore\n" + " --exclude: comma-separated list of filenames to ignore\n"
+ " --action validateExpectValid validate directory recursively expecting positive results \n" + " --action validateExpectValid validate directory recursively expecting positive results \n"
+ " [--no-notices]: refrain from reporting notices\n" + " [--no-notices]: refrain from reporting notices\n"
+ " Additional parameters (user will be prompted if not defined)\n" + " Additional parameters (user will be prompted if not defined)\n"
+ " -d, --directory to check recursively \n" + " -d, --directory to check recursively \n"
+ " Additional parameters (user will be prompted if not defined)\n" + " Additional parameters (user will be prompted if not defined)\n"
+ " --exclude: comma-separated list of filenames to ignore\n" + " --exclude: comma-separated list of filenames to ignore\n"
+ " --action visualize convert XML to HTML \n" + " --action visualize convert XML to HTML \n"
+ " [--language <lang>]: set output lang (en, fr or de)\n" + " [--language <lang>]: set output lang (en, fr or de)\n"
+ " [--source <filename>]: set input XML file\n" + " [--source <filename>]: set input XML file\n"
+ " [--out <filename>]: set output HTML file\n" + " [--out <filename>]: set output HTML file\n"
+ " --action pdf convert XML to PDF \n" + " --action pdf convert XML to PDF \n"
+ " [--source <filename>]: set input XML file\n" + " [--source <filename>]: set input XML file\n"
+ " [--out <filename>]: set output PDF file\n" + " [--out <filename>]: set output PDF file\n";
;
} }
private static void printHelp() { private static void printHelp() {
System.out.println("Mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + " \r\n" System.out.println("Mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + " \r\n"
+ "A Apache Public License tool for e-invoices with\r\n" + "A Apache Public License tool for e-invoices with\r\n"
+ "ZUGFeRD Metadata (http://www.zugferd.org)\r\n" + "\r\n" + getUsage() + "\r\n"); + "ZUGFeRD Metadata (http://www.zugferd.org)\r\n" + "\r\n" + getUsage() + "\r\n");
} }
/** /**
@@ -162,14 +161,16 @@ public class Main {
* Prompts the user for a input or output filename * Prompts the user for a input or output filename
* *
* @param prompt the text the user is asked * @param prompt the text the user is asked
* @param defaultFilename a default Filename. Passing an empty string indicates that specifying a file is optional * @param defaultFilename a default Filename. Passing an empty string
* @param expectedExtension will warn if filename does not match expected file extension, "or" possible with e.g. pdf|xml * indicates that specifying a file is optional
* @param expectedExtension will warn if filename does not match expected file
* extension, "or" possible with e.g. pdf|xml
* @param ensureFileExists will warn if file does NOT exist (for input files) * @param ensureFileExists will warn if file does NOT exist (for input files)
* @param ensureFileNotExists will warn if file DOES exist (for output files) * @param ensureFileNotExists will warn if file DOES exist (for output files)
* @return String * @return String
*/ */
protected static String getFilenameFromUser(String prompt, String defaultFilename, String expectedExtension, protected static String getFilenameFromUser(String prompt, String defaultFilename, String expectedExtension,
boolean ensureFileExists, boolean ensureFileNotExists) { boolean ensureFileExists, boolean ensureFileNotExists) {
boolean fileExistenceOK = false; boolean fileExistenceOK = false;
String selectedName = ""; String selectedName = "";
do { do {
@@ -187,7 +188,7 @@ public class Main {
if (selectedName.isEmpty()) { if (selectedName.isEmpty()) {
// pressed return without entering anything // pressed return without entering anything
if (defaultFilename.isEmpty()) { if (defaultFilename.isEmpty()) {
return ""; //no default -> this is an optional filename return ""; // no default -> this is an optional filename
} }
selectedName = defaultFilename; selectedName = defaultFilename;
} }
@@ -211,7 +212,7 @@ public class Main {
} }
} else if (!hasCorrectExtension) { } else if (!hasCorrectExtension) {
System.err.println("Expected " + expectedExtension System.err.println("Expected " + expectedExtension
+ " extension, this may corrupt your file. Do you still want to continue?(Y|N)"); + " extension, this may corrupt your file. Do you still want to continue?(Y|N)");
String selectedAnswer = ""; String selectedAnswer = "";
try { try {
selectedAnswer = buffer.readLine(); selectedAnswer = buffer.readLine();
@@ -270,6 +271,7 @@ public class Main {
/*** /***
* converts from CII to UBL * converts from CII to UBL
*
* @param xmlName the name of the xml file * @param xmlName the name of the xml file
* @param outName the name of the output file * @param outName the name of the output file
* @throws IOException * @throws IOException
@@ -309,7 +311,8 @@ public class Main {
} }
// Plain Java // Plain Java
// based on https://mkyong.com/java/how-to-convert-inputstream-to-string-in-java/ // based on
// https://mkyong.com/java/how-to-convert-inputstream-to-string-in-java/
private static String convertInputStreamToString(InputStream is) { private static String convertInputStreamToString(InputStream is) {
try (InputStream inputStream = is) { try (InputStream inputStream = is) {
int DEFAULT_BUFFER_SIZE = 8192; int DEFAULT_BUFFER_SIZE = 8192;
@@ -333,7 +336,9 @@ public class Main {
/*** /***
* the main function of the commandline tool... * the main function of the commandline tool...
* @param args the commandline args, see also https://www.mustangproject.org/commandline/#verbose *
* @param args the commandline args, see also
* https://www.mustangproject.org/commandline/#verbose
*/ */
public static void main(String[] args) { public static void main(String[] args) {
try { try {
@@ -347,12 +352,14 @@ public class Main {
options.addOption(new Option("f", "format", true, "which format to output")); options.addOption(new Option("f", "format", true, "which format to output"));
options.addOption(new Option("version", "version", true, "which version of the standard to use")); options.addOption(new Option("version", "version", true, "which version of the standard to use"));
options.addOption(new Option("profile", "profile", true, "which profile of the standard to use")); options.addOption(new Option("profile", "profile", true, "which profile of the standard to use"));
options.addOption(new Option("no-additional-attachments", "no-additional-attachments", false, "prevent prompting for attachments")); options.addOption(new Option("no-additional-attachments", "no-additional-attachments", false,
"prevent prompting for attachments"));
Option attachmentOpt = new Option("attachments", "attachments", true, "File attachments"); Option attachmentOpt = new Option("attachments", "attachments", true, "File attachments");
attachmentOpt.setValueSeparator(','); attachmentOpt.setValueSeparator(',');
attachmentOpt.setArgs(Option.UNLIMITED_VALUES); attachmentOpt.setArgs(Option.UNLIMITED_VALUES);
options.addOption(attachmentOpt); options.addOption(attachmentOpt);
Option excludeOpt = new Option("exclude", "exclude", true, "Files to exclude from recursive directory traversal"); Option excludeOpt = new Option("exclude", "exclude", true,
"Files to exclude from recursive directory traversal");
excludeOpt.setValueSeparator(','); excludeOpt.setValueSeparator(',');
excludeOpt.setArgs(Option.UNLIMITED_VALUES); excludeOpt.setArgs(Option.UNLIMITED_VALUES);
options.addOption(excludeOpt); options.addOption(excludeOpt);
@@ -361,8 +368,10 @@ public class Main {
options.addOption(new Option("language", "language", true, "output language (en, de or fr)")); options.addOption(new Option("language", "language", true, "output language (en, de or fr)"));
options.addOption(new Option("out", "out", true, "which output file to write to")); options.addOption(new Option("out", "out", true, "which output file to write to"));
options.addOption(new Option("no-notices", "no-notices", false, "suppress non-fatal errors")); options.addOption(new Option("no-notices", "no-notices", false, "suppress non-fatal errors"));
options.addOption(new Option("logAppend", "logAppend", true, "freeform text to be appended to log messages")); options.addOption(
options.addOption(new Option("disable-file-logging", "disable-file-logging", false, "suppress logging to file")); new Option("logAppend", "logAppend", true, "freeform text to be appended to log messages"));
options.addOption(
new Option("disable-file-logging", "disable-file-logging", false, "suppress logging to file"));
options.addOption(new Option("d", "directory", true, "which directory to operate on")); options.addOption(new Option("d", "directory", true, "which directory to operate on"));
options.addOption(new Option("i", "ignorefileextension", false, "ignore non-matching file extensions")); options.addOption(new Option("i", "ignorefileextension", false, "ignore non-matching file extensions"));
options.addOption(new Option("l", "listfromstdin", false, "take list of files from commandline")); options.addOption(new Option("l", "listfromstdin", false, "take list of files from commandline"));
@@ -378,7 +387,7 @@ public class Main {
// Retrieve all options // Retrieve all options
action = cmd.getOptionValue("action"); action = cmd.getOptionValue("action");
String directoryName = cmd.getOptionValue("directory"); String directoryName = cmd.getOptionValue("directory");
boolean filesFromStdIn = cmd.hasOption("listfromstdin");//((Number)cmdLine.getParsedOptionValue("integer-option")).intValue(); boolean filesFromStdIn = cmd.hasOption("listfromstdin");// ((Number)cmdLine.getParsedOptionValue("integer-option")).intValue();
boolean ignoreFileExt = cmd.hasOption("ignorefileextension"); boolean ignoreFileExt = cmd.hasOption("ignorefileextension");
boolean noAttachments = cmd.hasOption("no-additional-attachments"); boolean noAttachments = cmd.hasOption("no-additional-attachments");
boolean helpRequested = cmd.hasOption("help") || ((action != null) && (action.equals("help"))); boolean helpRequested = cmd.hasOption("help") || ((action != null) && (action.equals("help")));
@@ -398,11 +407,10 @@ public class Main {
String[] attachmentFilenames = cmd.hasOption("attachments") ? cmd.getOptionValues("attachments") : null; String[] attachmentFilenames = cmd.hasOption("attachments") ? cmd.getOptionValues("attachments") : null;
String[] excludedFilenames = cmd.hasOption("exclude") ? cmd.getOptionValues("exclude") : null; String[] excludedFilenames = cmd.hasOption("exclude") ? cmd.getOptionValues("exclude") : null;
ArrayList<FileAttachment> attachments = new ArrayList<>(); ArrayList<FileAttachment> attachments = new ArrayList<>();
/* /*
setting system property to disable FILE appender and * setting system property to disable FILE appender and
suppress creation of files and folders. * suppress creation of files and folders.
*/ */
System.setProperty("FILE_APPENDER_ENABLED", ((Boolean) (disableFileLogging == false)).toString()); System.setProperty("FILE_APPENDER_ENABLED", ((Boolean) (disableFileLogging == false)).toString());
@@ -411,14 +419,17 @@ public class Main {
if (helpRequested) { if (helpRequested) {
printHelp(); printHelp();
optionsRecognized = true; optionsRecognized = true;
} /* else if ((action!=null)&&(action.equals("license"))) { } /*
printLicense(); * else if ((action!=null)&&(action.equals("license"))) {
optionsRecognized=true; * printLicense();
} */ else if ((action != null) && (action.equals("metrics"))) { * optionsRecognized=true;
* }
*/ else if ((action != null) && (action.equals("metrics"))) {
performMetrics(directoryName, filesFromStdIn, ignoreFileExt); performMetrics(directoryName, filesFromStdIn, ignoreFileExt);
optionsRecognized = true; optionsRecognized = true;
} else if ((action != null) && (action.equals("combine"))) { } else if ((action != null) && (action.equals("combine"))) {
performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile, ignoreFileExt, attachmentFilenames, attachments, noAttachments); performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile,
ignoreFileExt, attachmentFilenames, attachments, noAttachments);
optionsRecognized = true; optionsRecognized = true;
} else if ((action != null) && (action.equals("extract"))) { } else if ((action != null) && (action.equals("extract"))) {
performExtract(sourceName, outName); performExtract(sourceName, outName);
@@ -439,7 +450,8 @@ public class Main {
performUBL(sourceName, outName); performUBL(sourceName, outName);
optionsRecognized = true; optionsRecognized = true;
} else if ((action != null) && (action.equals("validate"))) { } else if ((action != null) && (action.equals("validate"))) {
optionsRecognized = performValidate(sourceName, noNotices, cmd.getOptionValue("logAppend"), LogAsPDF); optionsRecognized = performValidate(sourceName, noNotices, cmd.getOptionValue("logAppend"),
LogAsPDF);
} else if ((action != null) && (action.equals("validateExpectValid"))) { } else if ((action != null) && (action.equals("validateExpectValid"))) {
optionsRecognized = performValidateExpect(true, directoryName, excludedFilenames); optionsRecognized = performValidateExpect(true, directoryName, excludedFilenames);
} else if ((action != null) && (action.equals("validateExpectInvalid"))) { } else if ((action != null) && (action.equals("validateExpectInvalid"))) {
@@ -466,7 +478,8 @@ public class Main {
} }
private static boolean performValidate(String sourceName, boolean noNotices, String logAppend, boolean createLogAsPDF) { private static boolean performValidate(String sourceName, boolean noNotices, String logAppend,
boolean createLogAsPDF) {
boolean optionsRecognized; boolean optionsRecognized;
if (sourceName == null) { if (sourceName == null) {
sourceName = getFilenameFromUser("Source PDF or XML", "invoice.pdf", "pdf|xml", true, false); sourceName = getFilenameFromUser("Source PDF or XML", "invoice.pdf", "pdf|xml", true, false);
@@ -482,7 +495,7 @@ public class Main {
String validationResultXML = zfv.validate(sourceName); String validationResultXML = zfv.validate(sourceName);
System.out.println(validationResultXML); System.out.println(validationResultXML);
if( createLogAsPDF) { if (createLogAsPDF) {
ValidationLogVisualizer vlvi = new ValidationLogVisualizer(); ValidationLogVisualizer vlvi = new ValidationLogVisualizer();
String fileBasename = FilenameUtils.getBaseName(sourceName); String fileBasename = FilenameUtils.getBaseName(sourceName);
@@ -516,7 +529,6 @@ public class Main {
return true; return true;
} }
private static void performConvert(String pdfName, String outName) throws IOException { private static void performConvert(String pdfName, String outName) throws IOException {
/* /*
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory() * ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
@@ -541,9 +553,9 @@ public class Main {
// All params are good! continue... // All params are good! continue...
try (ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1()) { try (ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1()) {
ze.convertOnly().load(pdfName); ze.convertOnly().load(pdfName);
ze.export(outName); ze.export(outName);
System.out.println("Written to " + outName); System.out.println("Written to " + outName);
} }
} }
@@ -579,7 +591,8 @@ public class Main {
} }
private static void performCombine(String pdfName, String xmlName, String outName, String format, String zfVersion, private static void performCombine(String pdfName, String xmlName, String outName, String format, String zfVersion,
String zfProfile, Boolean ignoreInputErrors, String[] attachmentFilenames, ArrayList<FileAttachment> attachments, Boolean noAttachments) throws Exception { String zfProfile, Boolean ignoreInputErrors, String[] attachmentFilenames,
ArrayList<FileAttachment> attachments, Boolean noAttachments) throws Exception {
/* /*
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory() * ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
* .setProducer("toecount") .setCreator(System.getProperty("user.name")) * .setProducer("toecount") .setCreator(System.getProperty("user.name"))
@@ -611,11 +624,13 @@ public class Main {
byte attachmentContents[] = null; byte attachmentContents[] = null;
String attachmentFilename, attachmentMime; String attachmentFilename, attachmentMime;
if (!noAttachments) { if (!noAttachments) {
attachmentFilename = getFilenameFromUser("Additional file attachments filename (empty for none)", "", "pdf", true, false); attachmentFilename = getFilenameFromUser("Additional file attachments filename (empty for none)",
"", "pdf", true, false);
if (attachmentFilename.length() != 0) { if (attachmentFilename.length() != 0) {
attachmentContents = Files.readAllBytes(Paths.get(attachmentFilename)); attachmentContents = Files.readAllBytes(Paths.get(attachmentFilename));
attachmentMime = Files.probeContentType(Paths.get(attachmentFilename)); attachmentMime = Files.probeContentType(Paths.get(attachmentFilename));
attachments.add(new FileAttachment(attachmentFilename, attachmentMime, "Data", attachmentContents)); attachments.add(
new FileAttachment(attachmentFilename, attachmentMime, "Data", attachmentContents));
} }
} }
} else { } else {
@@ -624,15 +639,17 @@ public class Main {
if (!attachmentFilename.isEmpty()) { if (!attachmentFilename.isEmpty()) {
byte[] attachmentContents = Files.readAllBytes(Paths.get(attachmentFilename)); byte[] attachmentContents = Files.readAllBytes(Paths.get(attachmentFilename));
String attachmentMime = Files.probeContentType(Paths.get(attachmentFilename)); String attachmentMime = Files.probeContentType(Paths.get(attachmentFilename));
attachments.add(new FileAttachment(attachmentFilename, attachmentMime, "Data", attachmentContents)); attachments.add(
new FileAttachment(attachmentFilename, attachmentMime, "Data", attachmentContents));
} }
} }
} }
if (format == null) { if (format == null) {
try { try {
format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD, ox=Order-X, da=Cross Industry Despatch Advice)", "fx", "fx|zf|ox|da"); format = getStringFromUser(
"Format (fx=Factur-X, zf=ZUGFeRD, ox=Order-X, da=Cross Industry Despatch Advice)", "fx",
"fx|zf|ox|da");
} catch (Exception e) { } catch (Exception e) {
LOGGER.error(e.getMessage(), e); LOGGER.error(e.getMessage(), e);
} }
@@ -642,7 +659,7 @@ public class Main {
if (zfVersion == null) { if (zfVersion == null) {
try { try {
zfVersion = getStringFromUser("Version (1 or 2)", "1", "1|2");//fx default version is 1 zfVersion = getStringFromUser("Version (1 or 2)", "1", "1|2");// fx default version is 1
} catch (Exception e) { } catch (Exception e) {
LOGGER.error(e.getMessage(), e); LOGGER.error(e.getMessage(), e);
} }
@@ -659,8 +676,10 @@ public class Main {
zfProfile = getStringFromUser("Profile (p)ilot", "p", "P|p"); zfProfile = getStringFromUser("Profile (p)ilot", "p", "P|p");
} else { } else {
zfProfile = getStringFromUser( zfProfile = getStringFromUser(
"Profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, EX[T]ENDED or [X]RECHNUNG", "E", "Profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n"
"M|m|W|w|B|b|C|c|E|e|T|t|X|x|"); + "[C]IUS, [E]N16931, EX[T]ENDED or [X]RECHNUNG",
"E",
"M|m|W|w|B|b|C|c|E|e|T|t|X|x|");
} }
} catch (Exception e) { } catch (Exception e) {
LOGGER.error(e.getMessage(), e); LOGGER.error(e.getMessage(), e);
@@ -670,7 +689,6 @@ public class Main {
} }
zfProfile = zfProfile.toLowerCase(); zfProfile = zfProfile.toLowerCase();
// Verify params // Verify params
ensureFileExists(pdfName); ensureFileExists(pdfName);
ensureFileExists(xmlName); ensureFileExists(xmlName);
@@ -738,7 +756,8 @@ public class Main {
} else { } else {
if (format.equals("fx")) { if (format.equals("fx")) {
zfIntVersion = 2;// actually we are talking of generation, not version zfIntVersion = 2;// actually we are talking of generation, not version
// so even if someone correctly requested factur-x 1 internally we call it zugferd 2 :-( // so even if someone correctly requested factur-x 1 internally we call it
// zugferd 2 :-(
} }
ze = new ZUGFeRDExporterFromPDFA(); ze = new ZUGFeRDExporterFromPDFA();
if (ignoreInputErrors) { if (ignoreInputErrors) {
@@ -748,16 +767,16 @@ public class Main {
ze.load(pdfName); ze.load(pdfName);
ze.setProducer("Mustang-cli") ze.setProducer("Mustang-cli")
.setZUGFeRDVersion(zfIntVersion) .setZUGFeRDVersion(zfIntVersion)
.setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile); .setCreator(System.getProperty("user.name")).setProfile(zfConformanceLevelProfile);
if (format.equals("zf")) { if (format.equals("zf")) {
ze.disableFacturX(); ze.disableFacturX();
} }
for (FileAttachment attachment : attachments) { for (FileAttachment attachment : attachments) {
ze.attachFile(attachment.getFilename(), attachment.getData(), attachment.getMimetype(), attachment.getRelation()); ze.attachFile(attachment.getFilename(), attachment.getData(), attachment.getMimetype(),
attachment.getRelation());
} }
ze.setXML(Files.readAllBytes(Paths.get(xmlName))); ze.setXML(Files.readAllBytes(Paths.get(xmlName)));
@@ -774,7 +793,7 @@ public class Main {
} }
private static void performMetrics(String directoryName, Boolean filesFromStdIn, Boolean ignoreFileExt) private static void performMetrics(String directoryName, Boolean filesFromStdIn, Boolean ignoreFileExt)
throws IOException { throws IOException {
StatRun sr = new StatRun(); StatRun sr = new StatRun();
if (ignoreFileExt) { if (ignoreFileExt) {
@@ -818,16 +837,14 @@ public class Main {
} else { } else {
System.out.println("ZUGFeRD XML source set to " + sourceName); System.out.println("ZUGFeRD XML source set to " + sourceName);
} }
if (!intoPDF) { if (lang == null) {
if (lang == null) { try {
try { lang = getStringFromUser("Output language", "en", "en|de|fr");
lang = getStringFromUser("Output language", "en", "en|de|fr"); } catch (Exception e) {
} catch (Exception e) { LOGGER.error(e.getMessage(), e);
LOGGER.error(e.getMessage(), e);
}
} else {
System.out.println("Output language set to " + lang);
} }
} else {
System.out.println("Output language set to " + lang);
} }
if (outName == null) { if (outName == null) {
@@ -855,18 +872,18 @@ public class Main {
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer(); ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
String xml = null; String xml = null;
try { try {
ZUGFeRDVisualizer.Language langCode = ZUGFeRDVisualizer.Language.EN;
if (lang.equalsIgnoreCase("de")) {
langCode = ZUGFeRDVisualizer.Language.DE;
}
if (lang.equalsIgnoreCase("fr")) {
langCode = ZUGFeRDVisualizer.Language.FR;
}
if (!intoPDF) { if (!intoPDF) {
ZUGFeRDVisualizer.Language langCode = ZUGFeRDVisualizer.Language.EN;
if (lang.equalsIgnoreCase("de")) {
langCode = ZUGFeRDVisualizer.Language.DE;
}
if (lang.equalsIgnoreCase("fr")) {
langCode = ZUGFeRDVisualizer.Language.FR;
}
xml = zvi.visualize(sourceName, langCode); xml = zvi.visualize(sourceName, langCode);
Files.write(Paths.get(outName), xml.getBytes()); Files.write(Paths.get(outName), xml.getBytes());
} else { } else {
zvi.toPDF(sourceName, outName); zvi.toPDF(sourceName, outName, langCode);
} }
} catch (Exception e) { } catch (Exception e) {
LOGGER.error(e.getMessage(), e); LOGGER.error(e.getMessage(), e);
@@ -880,13 +897,13 @@ public class Main {
ExportResource("/xrechnung-viewer.css"); ExportResource("/xrechnung-viewer.css");
ExportResource("/xrechnung-viewer.js"); ExportResource("/xrechnung-viewer.js");
System.out.println("xrechnung-viewer.css and xrechnung-viewer.js written as well (to local working dir)"); System.out
.println("xrechnung-viewer.css and xrechnung-viewer.js written as well (to local working dir)");
} catch (Exception e) { } catch (Exception e) {
LOGGER.error(e.getMessage(), e); LOGGER.error(e.getMessage(), e);
} }
} }
} }
/** /**
@@ -894,11 +911,14 @@ public class Main {
* *
* @param resourceName ie.: "/SmartLibrary.dll" * @param resourceName ie.: "/SmartLibrary.dll"
* @return The path to the exported resource * @return The path to the exported resource
* @throws Exception e.g. if the specified resource does not exist at the specified location * @throws Exception e.g. if the specified resource does not exist at the
* specified location
*/ */
static public String ExportResource(String resourceName) throws Exception { static public String ExportResource(String resourceName) throws Exception {
String jarFolder; String jarFolder;
try (InputStream stream = Main.class.getResourceAsStream(resourceName)) {//note that each / is a directory down in the "jar tree" been the jar the root of the tree try (InputStream stream = Main.class.getResourceAsStream(resourceName)) {// note that each / is a directory down
// in the "jar tree" been the jar
// the root of the tree
if (stream == null) { if (stream == null) {
throw new Exception("Cannot get resource \"" + resourceName + "\" from Jar file."); throw new Exception("Cannot get resource \"" + resourceName + "\" from Jar file.");
} }
@@ -907,9 +927,9 @@ public class Main {
byte[] buffer = new byte[4096]; byte[] buffer = new byte[4096];
jarFolder = System.getProperty("user.dir"); jarFolder = System.getProperty("user.dir");
try (FileOutputStream resStreamOut = new FileOutputStream(jarFolder + resourceName)) { try (FileOutputStream resStreamOut = new FileOutputStream(jarFolder + resourceName)) {
while ((readBytes = stream.read(buffer)) > 0) { while ((readBytes = stream.read(buffer)) > 0) {
resStreamOut.write(buffer, 0, readBytes); resStreamOut.write(buffer, 0, readBytes);
} }
} }
} }

View File

@@ -217,7 +217,7 @@ public class ZUGFeRDVisualizer {
} }
} }
protected String toFOP(String xmlFilename) protected String toFOP(String xmlFilename, Language lang)
throws IOException, TransformerException, ParserConfigurationException { throws IOException, TransformerException, ParserConfigurationException {
EStandard theStandard; EStandard theStandard;
try (FileInputStream fis = new FileInputStream(xmlFilename)) { try (FileInputStream fis = new FileInputStream(xmlFilename)) {
@@ -225,11 +225,11 @@ public class ZUGFeRDVisualizer {
} }
try (FileInputStream fis = new FileInputStream(xmlFilename)) { try (FileInputStream fis = new FileInputStream(xmlFilename)) {
return toFOP(fis, theStandard); return toFOP(fis, theStandard, lang);
} }
} }
protected String toFOP(InputStream is, EStandard theStandard) protected String toFOP(InputStream is, EStandard theStandard, Language lang)
throws TransformerException, IOException { throws TransformerException, IOException {
try { try {
@@ -256,12 +256,16 @@ public class ZUGFeRDVisualizer {
Optional<InputStream> in = copyStream(iaos); Optional<InputStream> in = copyStream(iaos);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (in.isPresent()) { if (in.isPresent()) {
applyXSLTToPDF(in.get(), baos); applyXSLTToPDF(in.get(), baos, lang);
} }
return baos.toString(StandardCharsets.UTF_8); return baos.toString(StandardCharsets.UTF_8);
} }
public void toPDF(String xmlFilename, String pdfFilename) { public void toPDF(String xmlFilename, String pdfFilename) {
toPDF(xmlFilename, pdfFilename, Language.DE);
}
public void toPDF(String xmlFilename, String pdfFilename, Language lang) {
// the writing part // the writing part
File XMLinputFile = new File(xmlFilename); File XMLinputFile = new File(xmlFilename);
@@ -272,7 +276,7 @@ public class ZUGFeRDVisualizer {
out from git with arbitrary options (which may include CSRF changes) out from git with arbitrary options (which may include CSRF changes)
*/ */
try { try {
fopInput = this.toFOP(XMLinputFile.getAbsolutePath()); fopInput = this.toFOP(XMLinputFile.getAbsolutePath(), lang);
} catch (TransformerException | IOException | ParserConfigurationException e) { } catch (TransformerException | IOException | ParserConfigurationException e) {
LOGGER.error("Failed to apply FOP", e); LOGGER.error("Failed to apply FOP", e);
} }
@@ -286,8 +290,12 @@ public class ZUGFeRDVisualizer {
return null; return null;
}, (OutputStream out) -> {}); }, (OutputStream out) -> {});
} }
public byte[] toPDF(String xmlContent) { public byte[] toPDF(String xmlContent) {
return toPDF(xmlContent, Language.DE);
}
public byte[] toPDF(String xmlContent, Language lang) {
String fopInput = null; String fopInput = null;
@@ -299,7 +307,7 @@ public class ZUGFeRDVisualizer {
EStandard theStandard = findOutStandardFromRootNode(fis); EStandard theStandard = findOutStandardFromRootNode(fis);
fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));//rewind :-( fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));//rewind :-(
fopInput = toFOP(fis, theStandard); fopInput = toFOP(fis, theStandard, lang);
} catch (TransformerException | IOException | ParserConfigurationException e) { } catch (TransformerException | IOException | ParserConfigurationException e) {
LOGGER.error("Failed to apply FOP", e); LOGGER.error("Failed to apply FOP", e);
} }
@@ -435,9 +443,10 @@ public class ZUGFeRDVisualizer {
xmlFile.close(); xmlFile.close();
} }
protected void applyXSLTToPDF(final InputStream xmlFile, final OutputStream PDFOutstream) protected void applyXSLTToPDF(final InputStream xmlFile, final OutputStream PDFOutstream, Language lang)
throws TransformerException, IOException { throws TransformerException, IOException {
Transformer transformer = mXsltPDFTemplate.newTransformer(); Transformer transformer = mXsltPDFTemplate.newTransformer();
transformer.setParameter("lang", lang.name().toLowerCase());
transformer.transform(new StreamSource(xmlFile), new StreamResult(PDFOutstream)); transformer.transform(new StreamSource(xmlFile), new StreamResult(PDFOutstream));
xmlFile.close(); xmlFile.close();

View File

@@ -0,0 +1,254 @@
<?xml version="1.0" encoding="UTF-8"?>
<properties>
<entry key="xr:Buyer_reference" id="BT-10">Référence acheteur</entry>
<entry key="xr:Buyer_name" id="BT-44">Nom</entry>
<entry key="xr:Buyer_address_line_1" id="BT-50">Adresse ligne 1</entry>
<entry key="xr:Buyer_address_line_2" id="BT-51">Adresse ligne 2</entry>
<entry key="xr:Buyer_address_line_3" id="BT-163">Adresse ligne 3</entry>
<entry key="xr:Buyer_post_code" id="BT-53">Code postal</entry>
<entry key="xr:Buyer_city" id="BT-52">Ville</entry>
<entry key="xr:Buyer_country_code" id="BT-55">Code pays</entry>
<entry key="xr:Buyer_identifier" id="BT-46">Identifiant</entry>
<entry key="xr:Buyer_identifier/@scheme_identifier" id="BT-46_scheme">Schéma de l'identifiant</entry>
<entry key="xr:Buyer_contact_point" id="BT-56">Nom</entry>
<entry key="xr:Buyer_contact_telephone_number" id="BT-57">Téléphone</entry>
<entry key="xr:Buyer_contact_email_address" id="BT-58">Adresse e-mail</entry>
<entry key="xr:Seller_name" id="BT-27">Raison sociale</entry>
<entry key="xr:Seller_address_line_1" id="BT-35">Adresse ligne 1</entry>
<entry key="xr:Seller_address_line_2" id="BT-36">Adresse ligne 2</entry>
<entry key="xr:Seller_address_line_3" id="BT-162">Adresse ligne 3</entry>
<entry key="xr:Seller_post_code" id="BT-38">Code postal</entry>
<entry key="xr:Seller_city" id="BT-37">Ville</entry>
<entry key="xr:Seller_country_subdivision" id="BT-39">Région</entry>
<entry key="xr:Seller_country_code" id="BT-40">Code pays</entry>
<entry key="xr:Seller_identifier" id="BT-29">Identifiant</entry>
<entry key="xr:Seller_identifier/@scheme_identifier" id="BT-29_scheme">Schéma de l'identifiant</entry>
<entry key="xr:Seller_contact_point" id="BT-41">Nom</entry>
<entry key="xr:Seller_contact_telephone_number" id="BT-42">Téléphone</entry>
<entry key="xr:Seller_contact_email_address" id="BT-43">Adresse e-mail</entry>
<entry key="xr:Invoice_number" id="BT-1">Numéro de facture</entry>
<entry key="xr:Invoice_issue_date" id="BT-2">Date de facture</entry>
<entry key="xr:Invoice_type_code" id="BT-3">Type de facture</entry>
<entry key="xr:Invoice_currency_code" id="BT-5">Devise</entry>
<entry key="xr:Project_reference" id="BT-11">Numéro de projet</entry>
<entry key="xr:Contract_reference" id="BT-12">Numéro de contrat</entry>
<entry key="xr:Purchase_order_reference" id="BT-13">Numéro de commande</entry>
<entry key="xr:Sales_order_reference" id="BT-14">Référence de commande client</entry>
<!-- Be aware that these are for the whole invoice -->
<entry key="xr:Invoicing_period_start_date" id="BT-73">Du</entry>
<entry key="xr:Invoicing_period_end_date" id="BT-74">Au</entry>
<entry key="xr:Preceding_Invoice_reference" id="BT-25">Numéro de facture</entry>
<entry key="xr:Preceding_Invoice_issue_date" id="BT-26">Date de facture</entry>
<entry key="xr:Sum_of_Invoice_line_net_amount" id="BT-106">Total des lignes</entry>
<entry key="xr:Sum_of_allowances_on_document_level" id="BT-107">Total des remises</entry>
<entry key="xr:Sum_of_charges_on_document_level" id="BT-108">Total des frais</entry>
<entry key="xr:Invoice_total_amount_without_VAT" id="BT-109">Total HT</entry>
<entry key="xr:Invoice_total_VAT_amount" id="BT-110">Total TVA</entry>
<entry key="xr:Invoice_total_VAT_amount_in_accounting_currency" id="BT-111">Total TVA en devise comptable</entry>
<entry key="xr:Invoice_total_amount_with_VAT" id="BT-112">Total TTC</entry>
<entry key="xr:Paid_amount" id="BT-113">Montant payé</entry>
<entry key="xr:Rounding_amount" id="BT-114">Montant d'arrondi</entry>
<entry key="xr:Amount_due_for_payment" id="BT-115">Montant dû</entry>
<entry key="xr:VAT_category_code" id="BT-118">Catégorie de TVA</entry>
<entry key="xr:VAT_category_taxable_amount" id="BT-116">Total</entry>
<entry key="xr:VAT_category_rate" id="BT-119">Taux de TVA</entry>
<entry key="xr:VAT_category_tax_amount" id="BT-117">Montant de TVA</entry>
<entry key="xr:VAT_exemption_reason_text" id="BT-120">Motif d'exonération</entry>
<entry key="xr:VAT_exemption_reason_code" id="BT-121">Code du motif d'exonération</entry>
<!-- Remises -->
<entry key="xr:Document_level_allowance_VAT_category_code" id="BT-95">Catégorie de TVA de la remise</entry>
<entry key="xr:Document_level_allowance_base_amount" id="BT-93">Montant de base</entry>
<entry key="xr:Document_level_allowance_percentage" id="BT-94">Pourcentage</entry>
<entry key="xr:Document_level_allowance_amount" id="BT-92">Remise</entry>
<entry key="xr:Document_level_allowance_VAT_rate" id="BT-96">Taux de TVA de la remise</entry>
<entry key="xr:Document_level_allowance_reason" id="BT-97">Motif de la remise</entry>
<entry key="xr:Document_level_allowance_reason_code" id="BT-98">Code du motif de la remise</entry>
<!-- Frais -->
<entry key="xr:Document_level_charge_VAT_category_code" id="BT-102">Catégorie de TVA des frais</entry>
<entry key="xr:Document_level_charge_base_amount" id="BT-100">Montant de base</entry>
<entry key="xr:Document_level_charge_percentage" id="BT-101">Pourcentage</entry>
<entry key="xr:Document_level_charge_amount" id="BT-99">Frais</entry>
<entry key="xr:Document_level_charge_VAT_rate" id="BT-103">Taux de TVA des frais</entry>
<entry key="xr:Document_level_charge_reason" id="BT-104">Motif des frais</entry>
<entry key="xr:Document_level_charge_reason_code" id="BT-105">Code du motif des frais</entry>
<entry key="xr:Payment_terms" id="BT-20">Escompte ; autres conditions de paiement</entry>
<entry key="xr:Payment_due_date" id="BT-9">Date d'échéance</entry>
<entry key="xr:Payment_means_type_code" id="BT-81">Code du moyen de paiement</entry>
<entry key="xr:Payment_means_text" id="BT-82">Moyen de paiement</entry>
<entry key="xr:Remittance_information" id="BT-83">Référence de paiement</entry>
<entry key="xr:Payment_card_primary_account_number" id="BT-87">Numéro de carte</entry>
<entry key="xr:Payment_card_holder_name" id="BT-88">Titulaire de la carte</entry>
<!-- BG-19 Direct Debit -->
<entry key="xr:Mandate_reference_identifier" id="BT-89">Référence du mandat</entry>
<entry key="xr:Debited_account_identifier" id="BT-91">IBAN</entry>
<entry key="xr:Bank_assigned_creditor_identifier" id="BT-90">Identifiant créancier</entry>
<!-- BG-17 Credit Transfer-->
<entry key="xr:Payment_account_name" id="BT-85">Titulaire du compte</entry>
<entry key="xr:Payment_account_identifier" id="BT-84">IBAN</entry>
<entry key="xr:Payment_service_provider_identifier" id="BT-86">BIC</entry>
<entry key="xr:Invoice_note_subject_code" id="BT-21">Objet</entry>
<entry key="xr:Invoice_note" id="BT-22">Remarque</entry>
<!-- BG-4 Seller and others -->
<entry key="xr:Seller_trading_name" id="BT-28">Nom commercial</entry>
<entry key="xr:Seller_electronic_address" id="BT-34">Adresse électronique</entry>
<entry key="xr:Seller_electronic_address/@scheme_identifier" id="BT-34_scheme">Schéma de l'adresse électronique</entry>
<entry key="xr:Seller_legal_registration_identifier" id="BT-30">Numéro SIRET/SIREN</entry>
<entry key="xr:Seller_legal_registration_identifier/@scheme_identifier" id="BT-30_scheme">Schéma du numéro d'enregistrement</entry>
<entry key="xr:Seller_VAT_identifier" id="BT-31">Numéro de TVA intracommunautaire</entry>
<entry key="xr:Seller_tax_registration_identifier" id="BT-32">Numéro fiscal</entry>
<entry key="xr:Seller_additional_legal_information" id="BT-33">Informations juridiques complémentaires</entry>
<entry key="xr:VAT_accounting_currency_code" id="BT-6">Code devise de la TVA</entry>
<!-- BG 12 and 11 Tax Representative party -->
<entry key="xr:Seller_tax_representative_name" id="BT-62">Nom</entry>
<entry key="xr:Tax_representative_address_line_1" id="BT-64">Adresse ligne 1</entry>
<entry key="xr:Tax_representative_address_line_2" id="BT-65">Adresse ligne 2</entry>
<entry key="xr:Tax_representative_address_line_3" id="BT-164">Adresse ligne 3</entry>
<entry key="xr:Tax_representative_post_code" id="BT-67">Code postal</entry>
<entry key="xr:Tax_representative_city" id="BT-66">Ville</entry>
<entry key="xr:Tax_representative_country_subdivision" id="BT-68">Région</entry>
<entry key="xr:Tax_representative_country_code" id="BT-69">Code pays</entry>
<entry key="xr:Seller_tax_representative_VAT_identifier" id="BT-63">Numéro de TVA intracommunautaire</entry>
<!-- Additional buyer information from different bgs -->
<entry key="xr:Buyer_trading_name" id="BT-45">Nom commercial</entry>
<entry key="xr:Buyer_country_subdivision" id="BT-54">Région</entry>
<entry key="xr:Buyer_electronic_address" id="BT-49">Adresse électronique</entry>
<entry key="xr:Buyer_electronic_address/@scheme_identifier" id="BT-49_scheme">Schéma de l'adresse électronique</entry>
<entry key="xr:Buyer_legal_registration_identifier" id="BT-47">Numéro SIRET/SIREN</entry>
<entry key="xr:Buyer_legal_registration_identifier/@scheme_identifier" id="BT-47_scheme">Schéma du numéro d'enregistrement</entry>
<entry key="xr:Buyer_VAT_identifier" id="BT-48">Numéro de TVA intracommunautaire</entry>
<entry key="xr:Value_added_tax_point_date" id="BT-7">Date d'exigibilité de la TVA</entry>
<entry key="xr:Value_added_tax_point_date_code" id="BT-8">Code de la date d'exigibilité de la TVA</entry>
<entry key="xr:Buyer_accounting_reference" id="BT-19">Référence comptable</entry>
<entry key="xr:Deliver_to_location_identifier" id="BT-71">Identifiant du lieu de livraison</entry>
<entry key="xr:Deliver_to_location_identifier/@scheme_identifier" id="BT-71_scheme">Schéma de l'identifiant</entry>
<entry key="xr:Actual_delivery_date" id="BT-72">Date de livraison</entry>
<entry key="xr:Deliver_to_party_name" id="BT-70">Nom du destinataire</entry>
<entry key="xr:Deliver_to_address_line_1" id="BT-75">Adresse ligne 1</entry>
<entry key="xr:Deliver_to_address_line_2" id="BT-76">Adresse ligne 2</entry>
<entry key="xr:Deliver_to_address_line_3" id="BT-165">Adresse ligne 3</entry>
<entry key="xr:Deliver_to_post_code" id="BT-78">Code postal</entry>
<entry key="xr:Deliver_to_city" id="BT-77">Ville</entry>
<entry key="xr:Deliver_to_country_subdivision" id="BT-79">Région</entry>
<entry key="xr:Deliver_to_country_code" id="BT-80">Code pays</entry>
<entry key="xr:Tender_or_lot_reference" id="BT-17">Numéro d'appel d'offres</entry>
<entry key="xr:Receiving_advice_reference" id="BT-15">Référence de l'avis de réception</entry>
<entry key="xr:Despatch_advice_reference" id="BT-16">Référence de l'avis d'expédition</entry>
<entry key="xr:Business_process_type" id="BT-23">Identifiant du processus</entry>
<entry key="xr:Specification_identifier" id="BT-24">Identifiant de spécification</entry>
<entry key="xr:Invoiced_object_identifier" id="BT-18">Identifiant de l'objet</entry>
<entry key="xr:Invoiced_object_identifier/@scheme_identifier" id="BT-18_scheme">Schéma de l'identifiant de l'objet</entry>
<!-- BG 10 -->
<entry key="xr:Payee_name" id="BT-59">Nom</entry>
<entry key="xr:Payee_identifier" id="BT-60">Identifiant</entry>
<entry key="xr:Payee_identifier/@scheme_identifier" id="BT-60_scheme">Schéma de l'identifiant</entry>
<entry key="xr:Payee_legal_registration_identifier" id="BT-61">Numéro SIRET/SIREN</entry>
<entry key="xr:Payee_legal_registration_identifier/@scheme_identifier" id="BT-61_scheme">Schéma du numéro d'enregistrement</entry>
<!-- BG 24 Additonal supporting Documents -->
<entry key="xr:Supporting_document_reference" id="BT-122">Identifiant</entry>
<entry key="xr:Supporting_document_description" id="BT-123">Description</entry>
<entry key="xr:External_document_location" id="BT-124">Référence (ex. adresse Internet)</entry>
<entry key="xr:Attached_document" id="BT-125">Document joint</entry>
<entry key="xr:Attached_document/@mime_code" id="BT-125_mime_code">Format du document joint</entry>
<entry key="xr:Attached_document/@filename" id="BT-125_filename">Nom du document joint</entry>
<entry key="xrv:zeitstempel">Date/Heure</entry>
<entry key="xrv:betreff">Objet</entry>
<entry key="xrv:text">Texte</entry>
<entry key="xrv:details">Détails</entry>
<entry key="xr:Invoice_line_identifier" id="BT-126">Position</entry>
<entry key="xr:Invoice_line_note" id="BT-127">Texte libre</entry>
<entry key="xr:Invoice_line_object_identifier" id="BT-128_identifier">Identifiant de l'objet</entry>
<entry key="xr:Invoice_line_object_identifier/@scheme_identifier" id="BT-128_scheme">Schéma de l'identifiant de l'objet</entry>
<entry key="xr:Referenced_purchase_order_line_reference" id="BT-132">Numéro de ligne de commande</entry>
<entry key="xr:Invoice_line_Buyer_accounting_reference" id="BT-133">Référence comptable</entry>
<entry key="xr:Invoice_line_period_start_date" id="BT-134">Du</entry>
<entry key="xr:Invoice_line_period_end_date" id="BT-135">Au</entry>
<entry key="xr:Invoiced_quantity" id="BT-129">Quantité</entry>
<entry key="xr:Invoiced_quantity_unit_of_measure_code" id="BT-130">Unité</entry>
<entry key="xr:Item_net_price" id="BT-146">Prix unitaire (HT)</entry>
<entry key="xr:Invoice_line_net_amount" id="BT-131">Prix total (HT)</entry>
<entry key="xr:Item_price_discount" id="BT-147">Remise (HT)</entry>
<entry key="xr:Item_gross_price" id="BT-148">Prix catalogue (HT)</entry>
<entry key="xr:Item_price_base_quantity" id="BT-149">Quantité de base</entry>
<entry key="xr:Item_price_base_quantity_unit_of_measure" id="BT-150">Code de l'unité de mesure</entry>
<entry key="xr:Invoiced_item_VAT_category_code" id="BT-151">TVA</entry>
<entry key="xr:Invoiced_item_VAT_rate" id="BT-152">Taux de TVA</entry>
<entry key="xr:Item_name" id="BT-153">Désignation</entry>
<entry key="xr:Item_description" id="BT-154">Description</entry>
<entry key="xr:Item_Sellers_identifier" id="BT-155">Référence article</entry>
<entry key="xr:Item_Buyers_identifier" id="BT-156">Référence article acheteur</entry>
<entry key="xr:Item_standard_identifier" id="BT-157">Identifiant article</entry>
<entry key="xr:Item_standard_identifier/@scheme_identifier" class="BT-157_scheme">Schéma de l'identifiant article</entry>
<entry key="xr:Item_classification_identifier" id="BT-158">Code de classification article</entry>
<entry key="xr:Item_classification_identifier/@scheme_identifier" id="BT-158_scheme">Identifiant du schéma</entry>
<entry key="xr:Item_classification_identifier/@scheme_version_identifier" id="BT-158_scheme_version">Version du schéma</entry>
<entry key="xr:Item_country_of_origin" id="BT-159">Code du pays d'origine</entry>
<entry key="xr:Invoice_line_allowance_base_amount" id="BT-137">Montant de base (HT)</entry>
<entry key="xr:Invoice_line_allowance_percentage" id="BT-138">Pourcentage</entry>
<entry key="xr:Invoice_line_allowance_amount" id="BT-136">Remise (HT)</entry>
<entry key="xr:Invoice_line_allowance_reason" id="BT-139">Motif de la remise</entry>
<entry key="xr:Invoice_line_allowance_reason_code" id="BT-140">Code du motif de la remise</entry>
<entry key="xr:Invoice_line_charge_base_amount" id="BT-142">Montant de base (HT)</entry>
<entry key="xr:Invoice_line_charge_percentage" id="BT-143">Pourcentage</entry>
<entry key="xr:Invoice_line_charge_amount" id="BT-141">Frais (HT)</entry>
<entry key="xr:Invoice_line_charge_reason" id="BT-144">Motif des frais</entry>
<entry key="xr:Invoice_line_charge_reason_code" id="BT-145">Code du motif des frais</entry>
<entry key="xr:Third_party_payment_type" id="BT-DEX-001">Type de créance tierce</entry>
<entry key="xr:Third_party_payment_amount" id="BT-DEX-002">Montant de la créance tierce</entry>
<entry key="xr:Third_party_payment_description" id="BT-DEX-003">Description de la créance tierce</entry>
<entry key="uebersicht">Données de la facture électronique</entry>
<entry key="uebersichtKaeufer" id="BG-7">Informations sur l'acheteur</entry>
<entry key="uebersichtVerkaeufer" id="BG-4">Informations sur le vendeur</entry>
<entry key="uebersichtRechnungsInfo" id="invoice-data">Données de facturation</entry>
<entry key="uebersichtRechnungsuebersicht" id="BG-22">Totaux de la facture</entry>
<entry key="uebersichtFremdleistungen" id="BG-DEX-09">Créance tierce</entry>
<entry key="uebersichtUmsatzsteuer" id="BG-23">Ventilation de la TVA au niveau de la facture</entry>
<entry key="uebersichtNachlass" id="BG-20">Remise au niveau de la facture</entry>
<entry key="uebersichtZuschlaege" id="BG-21">Frais au niveau de la facture</entry>
<entry key="uebersichtRechnungAbrechnungszeitraum">Période de facturation</entry>
<entry key="uebersichtRechnungVorausgegangeneRechnungen" id="BG-3">Factures précédentes</entry>
<entry key="uebersichtZahlungInfo" id="BG-4">Informations de paiement</entry>
<entry key="uebersichtZahlungKarte" id="BG-18">Informations carte</entry>
<entry key="uebersichtZahlungLastschrift" id="BG-19">Prélèvement</entry>
<entry key="uebersichtZahlungUeberweisung" id="BG-17">Virement</entry>
<entry key="uebersichtBemerkungen" id="BG-1">Remarques sur la facture</entry>
<entry key="details">Lignes de facture</entry>
<entry key="detailsPositionAbrechnungszeitraum" id="BG-26">Période de facturation</entry>
<entry key="detailsPositionPreiseinzelheiten" id="BG-29">Détails du prix</entry>
<entry key="detailsPositionNachlaesse" id="BG-27">Remises au niveau de la ligne de facture</entry>
<entry key="detailsPositionZuschlaege" id="BG-28">Frais au niveau de la ligne de facture</entry>
<entry key="detailsPositionArtikelinformationen" id="BG-31">Informations sur l'article</entry>
<entry key="detailsPositionArtikeleigenschaften" id="BG-32">Caractéristiques de l'article</entry>
<entry key="zusaetze">Compléments</entry>
<entry key="zusaetzeVerkaeufer" id="BG-4">Informations sur le vendeur</entry>
<entry key="zusaetzeSteuervertreter" id="BG-11">Représentant fiscal du vendeur</entry>
<entry key="zusaetzeKaeufer" id="BG-7">Informations sur l'acheteur</entry>
<entry key="zusaetzeLieferung" id="BG-13">Informations de livraison</entry>
<entry key="zusaetzeVertrag">Informations contractuelles</entry>
<entry key="zusaetzeZahlungsempfaenger" id="BG-10">Bénéficiaire différent du vendeur</entry>
<entry key="laufzettel">Fiche de suivi</entry>
<entry key="laufzettelHistorie">Historique de traitement</entry>
<entry key="anlagen">Pièces jointes</entry>
<entry key="anlagenListe">Documents justificatifs</entry>
<entry key="date-format">[D]/[M]/[Y]</entry>
<entry key="datetime-format">[D]/[M]/[Y] [H]:[m]:[s]</entry>
<entry key="amount-format">###.##0,00</entry>
<entry key="percentage-format">##0,00</entry>
<entry key="at-least-two-format">###.##0,#################</entry>
<entry key="sum-of-third-party-payment-amounts" id="BT-DEX-002_sum">Total des créances tierces</entry>
<entry key="_disclaimer">Nous déclinons toute responsabilité quant à l'exactitude des données.</entry>
<entry key="_invoice-note-group">Remarques sur la facture</entry>
<entry key="_open">Ouvrir</entry>
<entry key="no-data">Aucune donnée disponible</entry>
<entry key="_net">HT</entry>
<entry key="_gross">TTC</entry>
<entry key="_no-content">Les sections sans contenu ne sont pas affichées !</entry>
<entry key="_description">Description</entry>
<entry key="_price">Prix</entry>
<entry key="_price-unit">Unité de prix</entry>
<entry key="_vat">Taux TVA</entry>
<entry key="_tax-code">Code taxe</entry>
<entry key="_total">Total</entry>
<entry key="_page">Page</entry>
</properties>

View File

@@ -8,6 +8,7 @@
xmlns:xrf="https://projekte.kosit.org/xrechnung/xrechnung-visualization/functions"> xmlns:xrf="https://projekte.kosit.org/xrechnung/xrechnung-visualization/functions">
<xsl:decimal-format name="de" decimal-separator="," grouping-separator="." NaN="" /> <xsl:decimal-format name="de" decimal-separator="," grouping-separator="." NaN="" />
<xsl:decimal-format name="fr" decimal-separator="," grouping-separator="." NaN="" />
<xsl:decimal-format name="en" decimal-separator="." grouping-separator="," NaN="" /> <xsl:decimal-format name="en" decimal-separator="." grouping-separator="," NaN="" />
<xsl:template name="uebersicht"> <xsl:template name="uebersicht">

View File

@@ -1,176 +1,210 @@
/** /**
* ********************************************************************* * *********************************************************************
* <p> * <p>
* Copyright 2019 Jochen Staerk * Copyright 2019 Jochen Staerk
* <p> * <p>
* Use is subject to license terms. * Use is subject to license terms.
* <p> * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * 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 * 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. * of the License at http://www.apache.org/licenses/LICENSE-2.0.
* <p> * <p>
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* <p> * <p>
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* <p> * <p>
* ********************************************************************** * **********************************************************************
*/ */
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.junit.FixMethodOrder; import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters; import org.junit.runners.MethodSorters;
import org.mustangproject.ZUGFeRD.ZUGFeRDVisualizer.Language; import org.mustangproject.ZUGFeRD.ZUGFeRDVisualizer.Language;
import org.mustangproject.util.ByteArraySearcher; import org.mustangproject.util.ByteArraySearcher;
import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date; @FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class VisualizationTest extends ResourceCase {
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class VisualizationTest extends ResourceCase { final String TARGET_PDF_CII = "./target/testout-Visualization-cii.pdf";
final String TARGET_PDF_UBL = "./target/testout-Visualization-cii.pdf";
final String TARGET_PDF_CII = "./target/testout-Visualization-cii.pdf";
final String TARGET_PDF_UBL = "./target/testout-Visualization-cii.pdf"; public void testCIIVisualizationBasic() {
this.runZUGFeRDVisualization("factur-x.xml", "factur-x-vis.fr.html", Language.FR);
public void testCIIVisualizationBasic() { }
this.runZUGFeRDVisualization("factur-x.xml", "factur-x-vis.fr.html", Language.FR);
} public void testCIIVisualizationExtended() {
this.runZUGFeRDVisualization("factur-x-extended.xml", "factur-x-vis-extended.de.html", Language.DE);
public void testCIIVisualizationExtended() { }
this.runZUGFeRDVisualization("factur-x-extended.xml", "factur-x-vis-extended.de.html", Language.DE);
} public void testUBLCreditNoteVisualizationBasic() {
this.runZUGFeRDVisualization("ubl-creditnote.xml", "factur-x-vis-ubl-creditnote.en.html", Language.EN);
public void testUBLCreditNoteVisualizationBasic() { }
this.runZUGFeRDVisualization("ubl-creditnote.xml", "factur-x-vis-ubl-creditnote.en.html", Language.EN);
} public void testUBLVisualizationBasic() {
this.runZUGFeRDVisualization("ubl/01.01a-INVOICE.ubl.xml", "factur-x-vis-ubl.en.html", Language.EN);
public void testUBLVisualizationBasic() { }
this.runZUGFeRDVisualization("ubl/01.01a-INVOICE.ubl.xml", "factur-x-vis-ubl.en.html", Language.EN);
} private void runZUGFeRDVisualization(String inputFilename, String resultFileName, Language lang) {
File CIIinputFile = getResourceAsFile(inputFilename);
private void runZUGFeRDVisualization(String inputFilename, String resultFileName, Language lang) {
File CIIinputFile = getResourceAsFile(inputFilename); String expected = null;
String result = null;
String expected = null; try {
String result = null; ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
try { result = zvi.visualize(CIIinputFile.getAbsolutePath(), lang);
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer(); Files.write(Paths.get("./target/testout-" + resultFileName), result.getBytes(StandardCharsets.UTF_8));
result = zvi.visualize(CIIinputFile.getAbsolutePath(), lang);
Files.write(Paths.get("./target/testout-" + resultFileName), result.getBytes(StandardCharsets.UTF_8)); File expectedResult = getResourceAsFile(resultFileName);
expected = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8)
File expectedResult = getResourceAsFile(resultFileName); ;
expected = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8)
; } catch (UnsupportedOperationException e) {
fail("UnsupportedOperationException should not happen: " + e.getMessage());
} catch (UnsupportedOperationException e) { } catch (IllegalArgumentException e) {
fail("UnsupportedOperationException should not happen: " + e.getMessage()); fail("IllegalArgumentException should not happen: " + e.getMessage());
} catch (IllegalArgumentException e) { } catch (TransformerException e) {
fail("IllegalArgumentException should not happen: " + e.getMessage()); fail("TransformerException should not happen: " + e.getMessage());
} catch (TransformerException e) { } catch (IOException e) {
fail("TransformerException should not happen: " + e.getMessage()); fail("IOException should not happen: " + e.getMessage());
} catch (IOException e) { } catch (ParserConfigurationException e) {
fail("IOException should not happen: " + e.getMessage()); fail("ParserConfigurationException should not happen: " + e.getMessage());
} catch (ParserConfigurationException e) { }
fail("ParserConfigurationException should not happen: " + e.getMessage());
} assertNotNull(result);
/* remove file endings so that tests can also pass after checking
assertNotNull(result); out from git with arbitrary options (which may include CSRF changes)
/* remove file endings so that tests can also pass after checking */
out from git with arbitrary options (which may include CSRF changes) assertEquals(expected.replace("\r", "")
*/ .replace("\n", "")
assertEquals(expected.replace("\r", "") .replace("\t", "")
.replace("\n", "") .replace(" ", ""), result.replace("\r", "")
.replace("\t", "") .replace("\n", "")
.replace(" ", ""), result.replace("\r", "") .replace("\t", "")
.replace("\n", "") .replace(" ", ""));
.replace("\t", "") }
.replace(" ", ""));
}
public void testPDFVisualizationCII() {
File CIIinputFile = getResourceAsFile("cii/01.01a-INVOICE.cii.xml");
public void testPDFVisualizationCII() {
try {
File CIIinputFile = getResourceAsFile("cii/01.01a-INVOICE.cii.xml"); ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
zvi.toPDF(CIIinputFile.getAbsolutePath(), TARGET_PDF_CII);
// the writing part } catch (UnsupportedOperationException e) {
fail("UnsupportedOperationException should not happen: " + e.getMessage());
String expected = null; } catch (IllegalArgumentException e) {
String result = null; fail("IllegalArgumentException should not happen: " + e.getMessage());
try { }
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
zvi.toPDF(CIIinputFile.getAbsolutePath(), TARGET_PDF_CII); try {
} catch (UnsupportedOperationException e) { assertTrue(ByteArraySearcher.startsWith(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), new byte[]{'%', 'P', 'D', 'F'}));
fail("UnsupportedOperationException should not happen: " + e.getMessage()); assertTrue(ByteArraySearcher.contains(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), "<rdf:li>de</rdf:li>".getBytes()));
} catch (IllegalArgumentException e) { } catch (IOException e) {
fail("IllegalArgumentException should not happen: " + e.getMessage()); fail("IOException should not occur");
} }
}
try {
assertTrue(ByteArraySearcher.startsWith(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), new byte[]{'%', 'P', 'D', 'F'})); public void testPDFVisualizationCIIEnglish() {
} catch (IOException e) { File CIIinputFile = getResourceAsFile("cii/01.01a-INVOICE.cii.xml");
fail("IOException should not occur");
} try {
} ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
zvi.toPDF(CIIinputFile.getAbsolutePath(), TARGET_PDF_CII, Language.EN);
public void testPDFVisualizationUBL() { } catch (UnsupportedOperationException e) {
fail("UnsupportedOperationException should not happen: " + e.getMessage());
File UBLinputFile = getResourceAsFile("ubl/01.01a-INVOICE.ubl.xml"); } catch (IllegalArgumentException e) {
fail("IllegalArgumentException should not happen: " + e.getMessage());
// the writing part }
String sourceFilename = "factur-x.xml";
try {
String expected = null; assertTrue(ByteArraySearcher.startsWith(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), new byte[]{'%', 'P', 'D', 'F'}));
String result = null; assertTrue(ByteArraySearcher.contains(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), "<rdf:li>en</rdf:li>".getBytes()));
try { } catch (IOException e) {
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer(); fail("IOException should not occur");
zvi.toPDF(UBLinputFile.getAbsolutePath(), TARGET_PDF_UBL); }
} catch (UnsupportedOperationException e) { }
fail("UnsupportedOperationException should not happen: " + e.getMessage());
} catch (IllegalArgumentException e) { public void testPDFVisualizationCIIFrench() {
fail("IllegalArgumentException should not happen: " + e.getMessage()); File CIIinputFile = getResourceAsFile("cii/01.01a-INVOICE.cii.xml");
}
try {
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
try { zvi.toPDF(CIIinputFile.getAbsolutePath(), TARGET_PDF_CII, Language.FR);
assertTrue(ByteArraySearcher.startsWith(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), new byte[]{'%', 'P', 'D', 'F'})); } catch (UnsupportedOperationException e) {
} catch (IOException e) { fail("UnsupportedOperationException should not happen: " + e.getMessage());
fail("IOException should not occur"); } catch (IllegalArgumentException e) {
} fail("IllegalArgumentException should not happen: " + e.getMessage());
} }
public void testPDFVisualizationUBLCreditNote() { try {
assertTrue(ByteArraySearcher.startsWith(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), new byte[]{'%', 'P', 'D', 'F'}));
File UBLinputFile = getResourceAsFile("ubl/UBL-CreditNote-2.1-Example.ubl.xml"); assertTrue(ByteArraySearcher.contains(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), "<rdf:li>fr</rdf:li>".getBytes()));
} catch (IOException e) {
// the writing part fail("IOException should not occur");
String sourceFilename = "factur-x.xml"; }
}
String expected = null;
String result = null; public void testPDFVisualizationUBL() {
try {
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer(); File UBLinputFile = getResourceAsFile("ubl/01.01a-INVOICE.ubl.xml");
zvi.toPDF(UBLinputFile.getAbsolutePath(), TARGET_PDF_UBL);
} catch (UnsupportedOperationException e) { // the writing part
fail("UnsupportedOperationException should not happen: " + e.getMessage()); String sourceFilename = "factur-x.xml";
} catch (IllegalArgumentException e) {
fail("IllegalArgumentException should not happen: " + e.getMessage()); String expected = null;
} String result = null;
try {
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
try { zvi.toPDF(UBLinputFile.getAbsolutePath(), TARGET_PDF_UBL);
assertTrue(ByteArraySearcher.startsWith(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), new byte[]{'%', 'P', 'D', 'F'})); } catch (UnsupportedOperationException e) {
} catch (IOException e) { fail("UnsupportedOperationException should not happen: " + e.getMessage());
fail("IOException should not occur"); } catch (IllegalArgumentException e) {
} fail("IllegalArgumentException should not happen: " + e.getMessage());
} }
}
try {
assertTrue(ByteArraySearcher.startsWith(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), new byte[]{'%', 'P', 'D', 'F'}));
} catch (IOException e) {
fail("IOException should not occur");
}
}
public void testPDFVisualizationUBLCreditNote() {
File UBLinputFile = getResourceAsFile("ubl/UBL-CreditNote-2.1-Example.ubl.xml");
// the writing part
String sourceFilename = "factur-x.xml";
String expected = null;
String result = null;
try {
ZUGFeRDVisualizer zvi = new ZUGFeRDVisualizer();
zvi.toPDF(UBLinputFile.getAbsolutePath(), TARGET_PDF_UBL);
} catch (UnsupportedOperationException e) {
fail("UnsupportedOperationException should not happen: " + e.getMessage());
} catch (IllegalArgumentException e) {
fail("IllegalArgumentException should not happen: " + e.getMessage());
}
try {
assertTrue(ByteArraySearcher.startsWith(Files.readAllBytes(Paths.get(TARGET_PDF_CII)), new byte[]{'%', 'P', 'D', 'F'}));
} catch (IOException e) {
fail("IOException should not occur");
}
}
}