Merge branch 'master' into bugfix/issue841b

This commit is contained in:
Frank Langelage
2025-07-30 11:46:53 +02:00
committed by GitHub
40 changed files with 6751 additions and 1300 deletions

View File

@@ -1,17 +1,29 @@
2.18.1
=======
- #893 Tradeparty globalID is not read from JSON
2.18.0
=======
2025-07-14
- support parsing of BT-90 CreditorReferenceID
- #870
- #871
- #868
- #729
- #863
- #731
- #865
- #849
- #856
- #850/#843
- #855
- #874
- #876/830
- #871 schema validation does not ignore external entities
- #868 Fix wrong version in History.md
- #729 Updates about SpecifiedTradeSettlementHeaderMonetarySummation and SpecifiedTradeSettlementPaymentMeans
- #863 LineCalculator throws NPE if product is null (since 2.17.0)
- #731 Got a broken translation key when visualizing XML into PDF (xr:Business_process_type)
- #865 Add sevdesk signature to PDF creators
- #849 Ignore calculation errors when extracting xml from pdf
- #856 Read contact´s fax number.
- #850/#843 Correction for "Re-Initialize the HTML-template on language change
- #855 Suppress empty nodes in output XML
- #874 Skip PDNameTreeNodes if the names are null or empty
- #830 Invalid XML generated: Item vat-category-code summed up with other 0 percent category codes
- #878 report arithmetic issues in validation report
- corrected typo ArithmetricException to ArithmeticException
- #726 Financial account information (IBAN) is lost when converting a cii invoice to ubl
- #885 JSON duplicates on item allowances/charges
- #887 incorrect percentual item allowances
2.17.0
=======

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.17.1-SNAPSHOT</version>
<version>2.18.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
@@ -12,7 +12,7 @@
should also work for XRechnung/CII.
</name>
<packaging>jar</packaging>
<version>2.17.1-SNAPSHOT</version>
<version>2.18.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.compilerVersion>11</maven.compiler.compilerVersion>
@@ -23,7 +23,7 @@
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>validator</artifactId>
<version>2.17.1-SNAPSHOT</version>
<version>2.18.1-SNAPSHOT</version>
<!-- prototypes of new mustangproject versions can be installed by referring to them and installed to the local repo from a jar file with
mvn install:install-file -Dfile=mustang-1.5.4-SNAPSHOT.jar -DgroupId=org.mustangproject.ZUGFeRD -DartifactId=mustang -Dversion=1.5.4 -Dpackaging=jar -DgeneratePom=true
-->
@@ -106,8 +106,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<runOrder>alphabetical</runOrder>
<argLine>-Duser.timezone=UTC</argLine>
</configuration>
</plugin>
<!-- allow getImplementationVersion for the pom.xml -->

View File

@@ -371,17 +371,17 @@ public class Main {
boolean optionsRecognized = false;
String action = "";
Boolean disableFileLogging = false;
boolean disableFileLogging = false;
try {
cmd = parser.parse(options, args);
// Retrieve all options
action = cmd.getOptionValue("action");
String directoryName = cmd.getOptionValue("directory");
Boolean filesFromStdIn = cmd.hasOption("listfromstdin");//((Number)cmdLine.getParsedOptionValue("integer-option")).intValue();
Boolean ignoreFileExt = cmd.hasOption("ignorefileextension");
Boolean noAttachments = cmd.hasOption("no-additional-attachments");
Boolean helpRequested = cmd.hasOption("help") || ((action != null) && (action.equals("help")));
boolean filesFromStdIn = cmd.hasOption("listfromstdin");//((Number)cmdLine.getParsedOptionValue("integer-option")).intValue();
boolean ignoreFileExt = cmd.hasOption("ignorefileextension");
boolean noAttachments = cmd.hasOption("no-additional-attachments");
boolean helpRequested = cmd.hasOption("help") || ((action != null) && (action.equals("help")));
disableFileLogging = cmd.hasOption("disable-file-logging");
String sourceName = cmd.getOptionValue("source");
@@ -389,8 +389,8 @@ public class Main {
String outName = cmd.getOptionValue("out");
String format = cmd.getOptionValue("format");
String lang = cmd.getOptionValue("language");
Boolean noNotices = cmd.hasOption("no-notices");
Boolean LogAsPDF = cmd.hasOption("log-as-pdf");
boolean noNotices = cmd.hasOption("no-notices");
boolean LogAsPDF = cmd.hasOption("log-as-pdf");
String zugferdVersion = cmd.getOptionValue("version");
String zugferdProfile = cmd.getOptionValue("profile");

View File

@@ -68,7 +68,7 @@ public class ValidatorFileWalker
thisResultString = "invalid";
allValid = false;
}
LOGGER.info(String.format("\n@%s Testing file %d: %s (%s) ", dateFormat.format(date), fileCount++, thisResultString, file));
LOGGER.info("\n@{} Testing file {}: {} ({}) ", dateFormat.format(date), fileCount++, thisResultString, file);
}
}
}
@@ -79,7 +79,7 @@ public class ValidatorFileWalker
@Override
public FileVisitResult postVisitDirectory(Path dir,
IOException exc) {
LOGGER.info(String.format("\nDirectory: %s \n", dir));
LOGGER.info("\nDirectory: {} \n", dir);
return FileVisitResult.CONTINUE;
}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.17-->
<!--Created by yEd 3.21.1-->
<key attr.name="Beschreibung" attr.type="string" for="graph" id="d0"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
@@ -13,43 +13,37 @@
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<data key="d0"/>
<data key="d0" xml:space="preserve"/>
<node id="n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="137.0" x="120.375" y="0.0"/>
<y:Geometry height="54.0" width="137.0" x="411.5" y="0.0"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.83984375" x="38.580078125" y="17.93359375">PDF+XML<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.681640625" x="38.6591796875" xml:space="preserve" y="17.6494140625">PDF+XML<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n1" yfiles.foldertype="group">
<data key="d4"/>
<data key="d4" xml:space="preserve"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="264.666015625" width="366.0" x="1950.0" y="190.666015625"/>
<y:Geometry height="281.37646484375" width="364.0" x="1912.5" y="192.37646484375"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="366.0" x="0.0" y="0.0">ZUGFeRD</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="364.0" x="0.0" xml:space="preserve" y="0.0">ZUGFeRD</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 2</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.02685546875" x="-4.513427734375" xml:space="preserve" y="0.0">Folder 2</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
@@ -62,73 +56,55 @@
<node id="n1::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="1966.0" y="227.33203125"/>
<y:Geometry height="54.0" width="152.0" x="1927.5" y="229.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="100.73828125" x="25.630859375" y="17.93359375">Schematron files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="93.373046875" x="29.3134765625" xml:space="preserve" y="17.6494140625">Schematron files<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n1::n1">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="2148.0" y="386.33203125"/>
<y:Geometry height="54.0" width="152.0" x="2109.5" y="404.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="76.521484375" x="37.7392578125" y="17.93359375">Schema files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="72.6953125" x="39.65234375" xml:space="preserve" y="17.6494140625">Schema files<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n1::n2">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="1966.0" y="386.33203125"/>
<y:Geometry height="54.0" width="152.0" x="1927.5" y="404.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="85.615234375" x="33.1923828125" y="17.93359375">Codelist XMLs<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="81.361328125" x="35.3193359375" xml:space="preserve" y="17.6494140625">Codelist XMLs<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<node id="n2" yfiles.foldertype="group">
<data key="d4"/>
<data key="d4" xml:space="preserve"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="95.666015625" width="408.0" x="1512.0" y="195.666015625"/>
<y:Geometry height="96.37646484375" width="406.0" x="1476.5" y="197.37646484375"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="408.0" x="0.0" y="0.0">EN16931</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="406.0" x="0.0" xml:space="preserve" y="0.0">EN16931</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 3</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.02685546875" x="-4.513427734375" xml:space="preserve" y="0.0">Folder 3</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
@@ -141,57 +117,45 @@
<node id="n2::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="1731.0" y="232.33203125"/>
<y:Geometry height="44.0" width="173.0" x="1694.5" y="234.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="110.453125" x="31.2734375" y="12.93359375">CEF Codelist Excel<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="107.365234375" x="32.8173828125" xml:space="preserve" y="12.6494140625">CEF Codelist Excel<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n2::n1">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="1528.0" y="232.33203125"/>
<y:Geometry height="44.0" width="173.0" x="1491.5" y="234.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="100.2578125" x="36.37109375" y="12.93359375">CEN Schematron<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="97.369140625" x="37.8154296875" xml:space="preserve" y="12.6494140625">CEN Schematron<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<node id="n3" yfiles.foldertype="group">
<data key="d4"/>
<data key="d4" xml:space="preserve"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="95.666015625" width="205.0" x="2346.0" y="195.666015625"/>
<y:Geometry height="96.37646484375" width="203.0" x="2306.5" y="197.37646484375"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="205.0" x="0.0" y="0.0">UN/CEFACT</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="203.0" x="0.0" xml:space="preserve" y="0.0">UN/CEFACT</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 4</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.02685546875" x="-4.513427734375" xml:space="preserve" y="0.0">Folder 4</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
@@ -204,16 +168,10 @@
<node id="n3::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="2362.0" y="232.33203125"/>
<y:Geometry height="44.0" width="173.0" x="2321.5" y="234.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="76.521484375" x="48.2392578125" y="12.93359375">Schema files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="72.6953125" x="50.15234375" xml:space="preserve" y="12.6494140625">Schema files<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
@@ -222,39 +180,33 @@
<node id="n4">
<data key="d6">
<y:GenericNode configuration="BevelNode">
<y:Geometry height="54.0" width="163.75" x="474.625" y="641.33203125"/>
<y:Geometry height="54.0" width="163.75" x="350.3595238095238" y="675.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="70.638671875" x="46.5556640625" y="17.93359375">XML Report<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="68.025390625" x="47.8623046875" xml:space="preserve" y="17.6494140625">XML Report<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5" yfiles.foldertype="group">
<data key="d4"/>
<data key="d4" xml:space="preserve"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="493.33203125" width="1268.0" x="0.0" y="85.0"/>
<y:Geometry height="511.7529296875" width="1234.5" x="0.0" y="85.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="1268.0" x="0.0" y="0.0">ZUV</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="1234.5" x="0.0" xml:space="preserve" y="0.0">ZUV</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 5</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.02685546875" x="-4.513427734375" xml:space="preserve" y="0.0">Folder 5</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
@@ -267,167 +219,113 @@
<node id="n5::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="673.0" y="519.33203125"/>
<y:Geometry height="44.0" width="173.0" x="640.5" y="537.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="95.18359375" x="38.908203125" y="12.93359375">PH-Schematron<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="89.365234375" x="41.8173828125" xml:space="preserve" y="12.6494140625">PH-Schematron<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n1">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="84.0" x="801.25" y="386.33203125"/>
<y:Geometry height="54.0" width="84.0" x="801.5" y="404.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="28.24609375" x="27.876953125" y="17.93359375">XML<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="28.673828125" x="27.6630859375" xml:space="preserve" y="17.6494140625">XML<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n2">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="84.0" x="108.5" y="386.33203125"/>
<y:Geometry height="54.0" width="84.0" x="75.0" y="404.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="57.431640625" x="13.2841796875" y="17.93359375">Metadata<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="54.033203125" x="14.9833984375" xml:space="preserve" y="17.6494140625">Metadata<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n3">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="64.0" y="519.33203125"/>
<y:Geometry height="44.0" width="173.0" x="30.5" y="537.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="94.66796875" x="39.166015625" y="12.93359375">Metadata check<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="88.71484375" x="42.142578125" xml:space="preserve" y="12.6494140625">Metadata check<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n4">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="619.25" y="386.33203125"/>
<y:Geometry height="54.0" width="152.0" x="619.5" y="404.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.91015625" x="46.044921875" y="17.93359375">XSLT files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="58.685546875" x="46.6572265625" xml:space="preserve" y="17.6494140625">XSLT files<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n5">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="1100.0" y="386.33203125"/>
<y:Geometry height="54.0" width="152.0" x="1067.5" y="404.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.91015625" x="46.044921875" y="17.93359375">XSLT files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="58.685546875" x="46.6572265625" xml:space="preserve" y="17.6494140625">XSLT files<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n6">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="84.0" x="311.5" y="386.33203125"/>
<y:Geometry height="54.0" width="84.0" x="278.0" y="404.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="92.81640625" x="-4.408203125" y="17.93359375">Additional data<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="83.39453125" x="0.302734375" xml:space="preserve" y="17.6494140625">Additional data<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n7">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="267.0" y="519.33203125"/>
<y:Geometry height="44.0" width="173.0" x="233.5" y="537.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="130.052734375" x="21.4736328125" y="12.93359375">Additional data check<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="118.076171875" x="27.4619140625" xml:space="preserve" y="12.6494140625">Additional data check<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n8">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="876.0" y="519.33203125"/>
<y:Geometry height="44.0" width="173.0" x="843.5" y="537.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="95.18359375" x="38.908203125" y="12.93359375">PH-Schematron<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="89.365234375" x="41.8173828125" xml:space="preserve" y="12.6494140625">PH-Schematron<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n9" yfiles.foldertype="group">
<data key="d4"/>
<data key="d4" xml:space="preserve"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="169.666015625" width="205.0" x="251.0" y="121.666015625"/>
<y:Geometry height="171.37646484375" width="203.0" x="218.5" y="122.37646484375"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="205.0" x="0.0" y="0.0">Mustangproject</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="203.0" x="0.0" xml:space="preserve" y="0.0">Mustangproject</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 1</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.02685546875" x="-4.513427734375" xml:space="preserve" y="0.0">Folder 1</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
@@ -440,57 +338,45 @@
<node id="n5::n9::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="267.0" y="232.33203125"/>
<y:Geometry height="44.0" width="173.0" x="233.5" y="234.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="47.6875" x="62.65625" y="12.93359375">PDFBox<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="48.677734375" x="62.1611328125" xml:space="preserve" y="12.6494140625">PDFBox<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n9::n1">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="267.0" y="158.33203125"/>
<y:Geometry height="44.0" width="173.0" x="233.5" y="159.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="53.9453125" x="59.52734375" y="12.93359375">Mustang<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="50.025390625" x="61.4873046875" xml:space="preserve" y="12.6494140625">Mustang<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<node id="n5::n10" yfiles.foldertype="group">
<data key="d4"/>
<data key="d4" xml:space="preserve"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="95.666015625" width="205.0" x="16.0" y="121.666015625"/>
<y:Geometry height="96.37646484375" width="203.0" x="451.5" y="122.37646484375"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="205.0" x="0.0" y="0.0">VeraPDF</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="203.0" x="0.0" xml:space="preserve" y="0.0">VeraPDF</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 6</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.02685546875" x="-4.513427734375" xml:space="preserve" y="0.0">Folder 6</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
@@ -503,16 +389,10 @@
<node id="n5::n10::n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="32.0" y="158.33203125"/>
<y:Geometry height="44.0" width="173.0" x="466.5" y="159.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="52.123046875" x="60.4384765625" y="12.93359375">VeraPDF<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="53.34765625" x="59.826171875" xml:space="preserve" y="12.6494140625">VeraPDF<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
@@ -521,74 +401,66 @@
<node id="n5::n11">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="1079.0" y="519.33203125"/>
<y:Geometry height="44.0" width="173.0" x="1046.5" y="537.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="85.80859375" x="43.595703125" y="12.93359375">Schema check<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="82.703125" x="45.1484375" xml:space="preserve" y="12.6494140625">Schema check<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n12">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode3">
<y:Geometry height="54.0" width="152.0" x="437.25" y="386.33203125"/>
<y:Geometry height="54.0" width="152.0" x="437.5" y="404.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.91015625" x="46.044921875" y="17.93359375">XSLT files<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="58.685546875" x="46.6572265625" xml:space="preserve" y="17.6494140625">XSLT files<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n13">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="44.0" width="173.0" x="470.0" y="519.33203125"/>
<y:Geometry height="44.0" width="173.0" x="437.5" y="537.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="95.18359375" x="38.908203125" y="12.93359375">PH-Schematron<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="89.365234375" x="41.8173828125" xml:space="preserve" y="12.6494140625">PH-Schematron<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n5::n14">
<data key="d5"/>
<data key="d6">
<y:GenericNode configuration="BevelNode3">
<y:Geometry height="44.0" width="152.0" x="15.0" y="234.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="110.72265625" x="20.638671875" xml:space="preserve" y="12.6494140625">Intra-line calculation<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
</graph>
</node>
<node id="n6" yfiles.foldertype="group">
<data key="d4"/>
<data key="d5"/>
<data key="d4" xml:space="preserve"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="105.666015625" width="184.0" x="1298.0" y="190.666015625"/>
<y:Geometry height="106.37646484375" width="182.0" x="1264.5" y="192.37646484375"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="184.0" x="0.0" y="0.0">XRechnung</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="182.0" x="0.0" xml:space="preserve" y="0.0">XRechnung</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="1.0" right="1" rightF="1.0" top="0" topF="0.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 7</y:NodeLabel>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="t" textColor="#000000" verticalTextPosition="bottom" visible="true" width="59.02685546875" x="-4.513427734375" xml:space="preserve" y="0.0">Folder 7</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
@@ -599,19 +471,12 @@
</data>
<graph edgedefault="directed" id="n6:">
<node id="n6::n0">
<data key="d5"/>
<data key="d6">
<y:GenericNode configuration="BevelNode2">
<y:Geometry height="54.0" width="152.0" x="1314.0" y="227.33203125"/>
<y:Geometry height="54.0" width="152.0" x="1279.5" y="229.7529296875"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="72.7890625" x="39.60546875" y="17.93359375">Schematron<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="68.69921875" x="41.650390625" xml:space="preserve" y="17.6494140625">Schematron<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel>
</y:GenericNode>
</data>
</node>
@@ -621,8 +486,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="0.0" ty="-27.0">
<y:Point x="1817.5" y="370.83203125"/>
<y:Point x="2042.0" y="370.83203125"/>
<y:Point x="1781.0" y="389.2529296875"/>
<y:Point x="2003.5" y="389.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -634,8 +499,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="0.0" ty="-27.0">
<y:Point x="2448.5" y="306.83203125"/>
<y:Point x="2224.0" y="306.83203125"/>
<y:Point x="2408.0" y="309.2529296875"/>
<y:Point x="2185.5" y="309.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -647,8 +512,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="10.5" sy="27.0" tx="-57.66666666666667" ty="-22.0">
<y:Point x="853.75" y="487.83203125"/>
<y:Point x="904.8333333333334" y="487.83203125"/>
<y:Point x="854.0" y="506.2529296875"/>
<y:Point x="872.3333333333334" y="506.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -660,8 +525,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-10.5" sy="27.0" tx="43.25" ty="-22.0">
<y:Point x="832.75" y="487.83203125"/>
<y:Point x="802.75" y="487.83203125"/>
<y:Point x="833.0" y="506.2529296875"/>
<y:Point x="770.25" y="506.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -683,8 +548,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="-43.25" ty="-22.0">
<y:Point x="695.25" y="455.83203125"/>
<y:Point x="716.25" y="455.83203125"/>
<y:Point x="695.5" y="474.2529296875"/>
<y:Point x="683.75" y="474.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -696,8 +561,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="0.0" ty="-22.0">
<y:Point x="1176.0" y="455.83203125"/>
<y:Point x="962.5" y="455.83203125"/>
<y:Point x="1143.5" y="474.2529296875"/>
<y:Point x="930.0" y="474.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -729,8 +594,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-57.666666666666686" sy="22.0" tx="0.0" ty="-27.0">
<y:Point x="295.8333333333333" y="306.83203125"/>
<y:Point x="150.5" y="306.83203125"/>
<y:Point x="262.3333333333333" y="309.2529296875"/>
<y:Point x="117.0" y="309.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -742,8 +607,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="57.66666666666667" sy="22.0" tx="0.0" ty="-27.0">
<y:Point x="411.1666666666667" y="306.83203125"/>
<y:Point x="843.25" y="306.83203125"/>
<y:Point x="377.6666666666667" y="325.2529296875"/>
<y:Point x="843.5" y="325.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -754,7 +619,10 @@
<edge id="n5::n9::e0" source="n5::n9::n1" target="n5::n9::n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="0.0" ty="-22.0"/>
<y:Path sx="43.25" sy="22.0" tx="0.0" ty="-22.0">
<y:Point x="363.25" y="219.2529296875"/>
<y:Point x="320.0" y="219.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
@@ -764,9 +632,9 @@
<edge id="e2" source="n0" target="n5::n10::n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-34.25" sy="27.0" tx="0.0" ty="-22.0">
<y:Point x="154.625" y="69.5"/>
<y:Point x="118.5" y="69.5"/>
<y:Path sx="34.25" sy="27.0" tx="0.0" ty="-22.0">
<y:Point x="514.25" y="69.5"/>
<y:Point x="553.0" y="69.5"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -777,11 +645,9 @@
<edge id="e3" source="n5::n10::n0" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="-70.17857142857144" ty="-27.0">
<y:Point x="118.5" y="232.83203125"/>
<y:Point x="48.5" y="232.83203125"/>
<y:Point x="48.5" y="625.83203125"/>
<y:Point x="486.32142857142856" y="625.83203125"/>
<y:Path sx="0.0" sy="22.0" tx="-10.234375" ty="-27.0">
<y:Point x="553.0" y="309.2529296875"/>
<y:Point x="422.0" y="309.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -792,9 +658,9 @@
<edge id="e4" source="n0" target="n5::n9">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="34.25" sy="27.0" tx="-94.25" ty="-84.8330078125">
<y:Point x="223.125" y="69.5"/>
<y:Point x="259.25" y="69.5"/>
<y:Path sx="-34.25" sy="27.0" tx="87.0" ty="-85.688232421875">
<y:Point x="445.75" y="69.5"/>
<y:Point x="407.0" y="69.5"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -805,9 +671,9 @@
<edge id="e5" source="n5::n0" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="23.39285714285714" ty="-27.0">
<y:Point x="759.5" y="593.83203125"/>
<y:Point x="579.8928571428571" y="593.83203125"/>
<y:Path sx="0.0" sy="22.0" tx="30.703125" ty="-27.0">
<y:Point x="727.0" y="628.2529296875"/>
<y:Point x="462.9376488095238" y="628.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -818,9 +684,9 @@
<edge id="e6" source="n5::n7" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="-23.39285714285714" ty="-27.0">
<y:Point x="353.5" y="593.83203125"/>
<y:Point x="533.1071428571429" y="593.83203125"/>
<y:Path sx="0.0" sy="22.0" tx="-30.703125" ty="-27.0">
<y:Point x="320.0" y="612.2529296875"/>
<y:Point x="401.5313988095238" y="612.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -831,9 +697,9 @@
<edge id="e7" source="n5::n3" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="-46.785714285714285" ty="-27.0">
<y:Point x="150.5" y="609.83203125"/>
<y:Point x="509.7142857142857" y="609.83203125"/>
<y:Path sx="0.0" sy="22.0" tx="-51.171875" ty="-27.0">
<y:Point x="117.0" y="628.2529296875"/>
<y:Point x="381.0626488095238" y="628.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -844,9 +710,9 @@
<edge id="e8" source="n5::n8" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="46.78571428571428" ty="-27.0">
<y:Point x="962.5" y="609.83203125"/>
<y:Point x="603.2857142857142" y="609.83203125"/>
<y:Path sx="0.0" sy="22.0" tx="51.171875" ty="-27.0">
<y:Point x="930.0" y="644.2529296875"/>
<y:Point x="483.4063988095238" y="644.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -858,8 +724,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="0.0" ty="-27.0">
<y:Point x="1614.5" y="338.83203125"/>
<y:Point x="1176.0" y="338.83203125"/>
<y:Point x="1578.0" y="357.2529296875"/>
<y:Point x="1143.5" y="357.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -871,8 +737,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="0.0" ty="-27.0">
<y:Point x="2042.0" y="354.83203125"/>
<y:Point x="695.25" y="354.83203125"/>
<y:Point x="2003.5" y="373.2529296875"/>
<y:Point x="695.5" y="373.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -884,8 +750,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="31.5" sy="27.0" tx="-43.25" ty="-22.0">
<y:Point x="874.75" y="471.83203125"/>
<y:Point x="1122.25" y="471.83203125"/>
<y:Point x="875.0" y="490.2529296875"/>
<y:Point x="1089.75" y="490.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -896,9 +762,9 @@
<edge id="e11" source="n5::n11" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="70.17857142857142" ty="-27.0">
<y:Point x="1165.5" y="625.83203125"/>
<y:Point x="626.6785714285714" y="625.83203125"/>
<y:Path sx="0.0" sy="22.0" tx="71.640625" ty="-27.0">
<y:Point x="1133.0" y="660.2529296875"/>
<y:Point x="503.8751488095238" y="660.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -910,8 +776,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="43.25" ty="-22.0">
<y:Point x="2224.0" y="503.83203125"/>
<y:Point x="1208.75" y="503.83203125"/>
<y:Point x="2185.5" y="522.2529296875"/>
<y:Point x="1176.25" y="522.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -923,8 +789,8 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="57.666666666666686" ty="-22.0">
<y:Point x="2042.0" y="487.83203125"/>
<y:Point x="1020.1666666666667" y="487.83203125"/>
<y:Point x="2003.5" y="506.2529296875"/>
<y:Point x="987.6666666666667" y="506.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -933,13 +799,12 @@
</data>
</edge>
<edge id="e14" source="n6::n0" target="n5::n12">
<data key="d8"/>
<data key="d9"/>
<data key="d8" xml:space="preserve"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="0.0" ty="-27.0">
<y:Point x="1390.0" y="322.83203125"/>
<y:Point x="513.25" y="322.83203125"/>
<y:Point x="1355.5" y="341.2529296875"/>
<y:Point x="513.5" y="341.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -948,11 +813,13 @@
</data>
</edge>
<edge id="n5::e10" source="n5::n12" target="n5::n13">
<data key="d8"/>
<data key="d9"/>
<data key="d8" xml:space="preserve"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="27.0" tx="-43.25" ty="-22.0"/>
<y:Path sx="0.0" sy="27.0" tx="-43.25" ty="-22.0">
<y:Point x="513.5" y="474.2529296875"/>
<y:Point x="480.75" y="474.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
@@ -960,13 +827,12 @@
</data>
</edge>
<edge id="n5::e11" source="n5::n1" target="n5::n13">
<data key="d8"/>
<data key="d9"/>
<data key="d8" xml:space="preserve"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-31.5" sy="27.0" tx="43.25" ty="-22.0">
<y:Point x="811.75" y="471.83203125"/>
<y:Point x="599.75" y="471.83203125"/>
<y:Point x="812.0" y="490.2529296875"/>
<y:Point x="567.25" y="490.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
@@ -975,11 +841,43 @@
</data>
</edge>
<edge id="e15" source="n5::n13" target="n4">
<data key="d8"/>
<data key="d8" xml:space="preserve"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="10.234375" ty="-27.0">
<y:Point x="524.0" y="612.2529296875"/>
<y:Point x="442.4688988095238" y="612.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n5::e12" source="n5::n9::n1" target="n5::n14">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="0.0" ty="-27.0"/>
<y:Path sx="-43.25" sy="22.0" tx="0.0" ty="-22.0">
<y:Point x="276.75" y="219.2529296875"/>
<y:Point x="91.0" y="219.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e16" source="n5::n14" target="n4">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="22.0" tx="-71.640625" ty="-27.0">
<y:Point x="91.0" y="294.2529296875"/>
<y:Point x="15.0" y="294.2529296875"/>
<y:Point x="15.0" y="644.2529296875"/>
<y:Point x="360.5938988095238" y="644.2529296875"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 608 KiB

View File

@@ -57,12 +57,26 @@ to validate the XML part of the invoices.
![Architecture of the validator](ZUV-Architektur.svg "Graph of the architecture of the validator component")
## New build
## Aspects
Apart from the fact that apart from
* the code
* we need tests and apart from implementing it in
Target platform is java 1.17
* the interface
* usually we need functionality in or via the invoice class.
Reading should work for both
* CII and
* UBL
And when writing,
* it should be readable as well, usually in the invoiceimporter,
* and it should be readable and writeable via Jackson (i.e. JSON)
## Build
Target platform is java 1.17
The package can be build with
```
mvnw clean package
@@ -184,7 +198,6 @@ maybe not yet even existing new release version:
```
cd validator/target
mvn install:install-file -Dfile=validator-2.17.0-SNAPSHOT-shaded.jar -Dclassifier=shaded -DgroupId="org.mustangproject" -DartifactId=validator -Dversion="2.17.0" -Dpackaging=jar -DgeneratePom=true
```
In gradle you can use something like
```

View File

@@ -3,13 +3,13 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.17.1-SNAPSHOT</version>
<version>2.18.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.17.1-SNAPSHOT</version>
<version>2.18.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Library to write, read and validate e-invoices (Factur-X, ZUGFeRD, Order-X, XRechnung/CII)</name>
<description>FOSS Java library to read, write and validate european electronic invoices and orders in the UN/CEFACT
@@ -137,6 +137,12 @@
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>2.0-rc1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
@@ -173,8 +179,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<runOrder>alphabetical</runOrder>
<argLine>-Duser.timezone=UTC</argLine>
</configuration>
</plugin>
<plugin>

View File

@@ -38,7 +38,7 @@ public class Allowance extends Charge {
if(totalAmount != null) {
return totalAmount;
} else if (percent!=null) {
BigDecimal singlePrice=currentItem.getValue().divide(BigDecimal.ONE.add(getPercent().divide(new BigDecimal(100))), 18, RoundingMode.HALF_UP);
BigDecimal singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100))));
// BigDecimal singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100))));
BigDecimal singlePriceDiff=currentItem.getValue().subtract(singlePrice);
return singlePriceDiff;

View File

@@ -145,10 +145,9 @@ public class Charge implements IZUGFeRDAllowanceCharge {
if(totalAmount != null) {
return totalAmount;
} else if (percent!=null) {
BigDecimal singlePrice=currentItem.getValue().divide(BigDecimal.ONE.add(getPercent().divide(new BigDecimal(100))), 18, RoundingMode.HALF_UP);
// BigDecimal singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100))));
BigDecimal singlePriceDiff=currentItem.getValue().add(singlePrice);
return singlePriceDiff;
BigDecimal factor=getPercent().divide(new BigDecimal(100), 18, RoundingMode.HALF_UP);
BigDecimal singlePrice=currentItem.getValue().multiply(factor);
return singlePrice;
} else {
throw new RuntimeException("percent must be set");
}

View File

@@ -0,0 +1,17 @@
package org.mustangproject.Exceptions;
import java.text.ParseException;
/***
* will be thrown if an invoice cant be reproduced numerically
* ArithmetricException for backwards compatibility, was a spelling error
*/
public class ArithmeticException extends ArithmetricException {
public ArithmeticException() {
super();
}
public ArithmeticException(String details) {
super(details);
}
}

View File

@@ -4,6 +4,7 @@ import java.text.ParseException;
/***
* will be thrown if an invoice cant be reproduced numerically
* (deprecated, because of typo)
*/
public class ArithmetricException extends ParseException {
public ArithmetricException() {

View File

@@ -591,11 +591,7 @@ public class Invoice implements IExportableTransaction {
* @return fluent setter
*/
public Invoice setZFAllowances(Allowance[] iza) {
Allowances=new ArrayList<>();
for (IZUGFeRDAllowanceCharge cz:iza) {
Allowances.add(cz);
}
Allowances=new ArrayList<>(Arrays.asList(iza));
return this;
}
@@ -616,9 +612,7 @@ public class Invoice implements IExportableTransaction {
*/
public Invoice setZFCharges(Charge[] iza) {
Charges=new ArrayList<>();
for (IZUGFeRDAllowanceCharge cz:iza) {
Charges.add(cz);
}
Charges.addAll(Arrays.asList(iza));
return this;
}

View File

@@ -1,5 +1,6 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IReferencedDocument;
@@ -77,20 +78,21 @@ public class Item implements IZUGFeRDExportableItem {
icnm.getAsString("Name").ifPresent(product::setName);
icnm.getAsString("Description").ifPresent(product::setDescription);
icnm.getAsNodeMap("SellersItemIdentification").ifPresent(SellersItemIdentification -> {
SellersItemIdentification.getAsString("ID").ifPresent(product::setSellerAssignedID);
});
icnm.getAsNodeMap("SellersItemIdentification")
.flatMap(SellersItemIdentification -> SellersItemIdentification.getAsString("ID"))
.ifPresent(product::setSellerAssignedID);
icnm.getAsNodeMap("BuyersItemIdentification").ifPresent(BuyersItemIdentification -> {
BuyersItemIdentification.getAsString("ID").ifPresent(product::setBuyerAssignedID);
});
icnm.getAsNodeMap("BuyersItemIdentification")
.flatMap(BuyersItemIdentification -> BuyersItemIdentification.getAsString("ID"))
.ifPresent(product::setBuyerAssignedID);
icnm.getAsNodeMap("ClassifiedTaxCategory").flatMap(m -> m.getAsBigDecimal("Percent"))
icnm.getAsNodeMap("ClassifiedTaxCategory")
.flatMap(m -> m.getAsBigDecimal("Percent"))
.ifPresent(product::setVATPercent);
});
itemMap.getAsNodeMap("AssociatedDocumentLineDocument").ifPresent(icnm -> {
icnm.getAsString("LineID").ifPresent(this::setId);
});
itemMap.getAsNodeMap("AssociatedDocumentLineDocument")
.flatMap(icnm -> icnm.getAsString("LineID"))
.ifPresent(this::setId);
itemMap.getAsNodeMap("Price").ifPresent(icnm -> {
// ubl
@@ -118,10 +120,16 @@ public class Item implements IZUGFeRDExportableItem {
itemMap.getAsString("ID")
.ifPresent(this::setId);
itemMap.getAsString("Note")
.ifPresent(this::addNote);
if (product==null) { // CII
if (itemMap.getNode("SpecifiedTradeProduct").isPresent()) {
product = new Product(itemMap.getNode("SpecifiedTradeProduct").get());
} else {
product = new Product();
}
}
itemMap.getAsNodeMap("SpecifiedLineTradeAgreement", "SpecifiedSupplyChainTradeAgreement").ifPresent(icnm -> {
icnm.getAsNodeMap("BuyerOrderReferencedDocument")
@@ -136,14 +144,29 @@ public class Item implements IZUGFeRDExportableItem {
npptpNodes.getAsBigDecimal("ChargeAmount").ifPresent(this::setPrice);
npptpNodes.getAsBigDecimal("BasisQuantity").ifPresent(this::setBasisQuantity);
});
icnm.getAsNodeMap("GrossPriceProductTradePrice").ifPresent(gpptpNodes -> {
gpptpNodes.getAsNodeMap("AppliedTradeAllowanceCharge").ifPresent(gpptpAtacNodes -> {
/** mustang attributes differences between net and gross price to the product */
String chargeIndicator = gpptpAtacNodes.getAsStringOrNull("ChargeIndicator");
if ((chargeIndicator != null)&&(gpptpAtacNodes.getAsBigDecimal("ActualAmount").isPresent())) {
BigDecimal actual = gpptpAtacNodes.getAsBigDecimal("ActualAmount").get();
if (chargeIndicator.equals("true")) {
product.addCharge(new Charge(actual));
setPrice(getPrice().subtract(actual)); // the gross price affects the net price, which is read,
// so if we do not ignore charges|allowances we have to re-compensate the net price
} else {
product.addAllowance(new Allowance(actual));
setPrice(getPrice().add(actual));
}
}
});
});
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).
forEach(this::addReferencedDocument);
});
itemMap.getNode("SpecifiedTradeProduct").map(Product::new).ifPresent(this::setProduct);//CII
itemMap.getNode("SpecifiedTradeProduct").map(Product::new).ifPresent(this::setProduct);//UBL
// RequestedQuantity is for Order-X, BilledQuantity for FX and ZF
itemMap.getAsNodeMap("SpecifiedLineTradeDelivery", "SpecifiedSupplyChainTradeDelivery")
.flatMap(icnm -> icnm.getNode("BilledQuantity", "RequestedQuantity", "DespatchedQuantity"))
@@ -180,7 +203,7 @@ public class Item implements IZUGFeRDExportableItem {
}
if (amountString != null) {
izac.setTotalAmount(new BigDecimal(amountString));
if (percentString!=null&&(percentString!="0")) {
if (percentString != null && (!percentString.equals("0"))) {
izac.setTotalAmount(new BigDecimal(amountString).divide(getQuantity()));
}
}
@@ -210,16 +233,16 @@ public class Item implements IZUGFeRDExportableItem {
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).forEach(this::addAdditionalReference);
icnm.getAsString("ReceivableSpecifiedTradeAccountingAccount").ifPresent(s -> this.accountingReference = s == null ? null : s.trim());
icnm.getAsString("ReceivableSpecifiedTradeAccountingAccount").ifPresent(s -> this.accountingReference = s.trim());
icnm.getAsNodeMap("BillingSpecifiedPeriod").ifPresent(periodNode -> {
Date start = periodNode.getAsNodeMap("StartDateTime").flatMap(dateTimeNode -> dateTimeNode.getNode("DateTimeString")).map(dts -> XMLTools.tryDate(dts)).orElse(null);
Date end = periodNode.getAsNodeMap("EndDateTime").flatMap(dateTimeNode -> dateTimeNode.getNode("DateTimeString")).map(dts -> XMLTools.tryDate(dts)).orElse(null);
Date start = periodNode.getAsNodeMap("StartDateTime").flatMap(dateTimeNode -> dateTimeNode.getNode("DateTimeString")).map(XMLTools::tryDate).orElse(null);
Date end = periodNode.getAsNodeMap("EndDateTime").flatMap(dateTimeNode -> dateTimeNode.getNode("DateTimeString")).map(XMLTools::tryDate).orElse(null);
setDetailedDeliveryPeriod(start, end);
});
});
itemMap.getAllNodes("AllowanceCharge").map(NodeMap::new).forEach(stac -> { //UBL
itemMap.getAllNodes("AllowanceCharge").map(NodeMap::new).forEach(stac -> { //CII
String isChargeString = stac.getAsString("ChargeIndicator").get();
String percentString = stac.getAsStringOrNull("MultiplierFactorNumeric");
@@ -301,13 +324,17 @@ public class Item implements IZUGFeRDExportableItem {
return this;
}
@Override public IZUGFeRDAllowanceCharge[] getAllowances() {
IZUGFeRDAllowanceCharge[] izac=new IZUGFeRDAllowanceCharge[Allowances.size()];
@JsonIgnore
@Override
public IZUGFeRDAllowanceCharge[] getAllowances() { // in JSON is already returned as itemAllowances (and only read from there)
IZUGFeRDAllowanceCharge[] izac = new IZUGFeRDAllowanceCharge[Allowances.size()];
return Allowances.toArray(izac);
}
@Override public IZUGFeRDAllowanceCharge[] getCharges() {
IZUGFeRDAllowanceCharge[] izac=new IZUGFeRDAllowanceCharge[Charges.size()];
@JsonIgnore
@Override
public IZUGFeRDAllowanceCharge[] getCharges() { // in JSON is already returned as itemAllowances (and only read from there)
IZUGFeRDAllowanceCharge[] izac = new IZUGFeRDAllowanceCharge[Charges.size()];
return Charges.toArray(izac);
}
@@ -425,9 +452,7 @@ public class Item implements IZUGFeRDExportableItem {
public void setItemAllowances(ArrayList<Allowance> theAllowances) {
if (theAllowances != null) {
Allowances.clear();
for (Allowance theAllowance : theAllowances) {
Allowances.add(theAllowance);
}
Allowances.addAll(theAllowances);
}
}
@@ -437,9 +462,7 @@ public class Item implements IZUGFeRDExportableItem {
public void setItemCharges(ArrayList<Charge> theCharges) {
if (theCharges != null) {
Charges.clear();
for (Charge theCharge : theCharges) {
Charges.add(theCharge);
}
Charges.addAll(theCharges);
}
}

View File

@@ -1,13 +1,10 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.*;
import org.mustangproject.ZUGFeRD.IDesignatedProductClassification;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableProduct;
import org.mustangproject.util.NodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.math.BigDecimal;
import java.util.ArrayList;
@@ -107,7 +104,10 @@ public class Product implements IZUGFeRDExportableProduct {
classifications.add(new DesignatedProductClassification(classCode, className)));
});
nodeMap.getAsString("OriginTradeCounty").ifPresent(this::setCountryOfOrigin);
nodeMap.getAsNodeMap("OriginTradeCountry")
.flatMap(nodes -> nodes.getNode("ID"))
.map(Node::getTextContent)
.ifPresent(this::setCountryOfOrigin);
}
/***
@@ -406,6 +406,16 @@ public class Product implements IZUGFeRDExportableProduct {
return this;
}
/***
* Jackson courtesy function, please use addCharge if you have the choice
* @return array of or null, if none
*/
public Product setCharges(ArrayList<Charge> charges) {
this.charges=charges;
return this;
}
/***
* returns the AppliedTradeAllowanceCharges of this product which are actually Charges
* @return array of or null, if none
@@ -432,5 +442,13 @@ public class Product implements IZUGFeRDExportableProduct {
return allowances.toArray(allowanceArr);
}
/***
* Jackson courtesy function, please use addAllowance if you have the choice
* @return array of or null, if none
*/
public Product setAllowances(ArrayList<Allowance> allowances) {
this.allowances=allowances;
return this;
}
}

View File

@@ -541,6 +541,32 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
return this;
}
/***
* for jackson, primarily, use addGlobalID(SchemedID) instead
* @param ID the id part without scheme
* @return fluent setter
*/
public TradeParty setGlobalID(String ID) {
if (globalId==null) {
globalId=new SchemedID();
}
globalId.setId(ID);
return this;
}
/***
* for jackson, primarily, use addGlobalID(SchemedID) instead
* @param scheme the scheme part without id
* @return fluent setter
*/
public TradeParty setGlobalIDScheme(String scheme) {
if (globalId==null) {
globalId=new SchemedID();
}
globalId.setScheme(scheme);
return this;
}
public TradeParty addGlobalID(SchemedID schemedID) {
globalId = schemedID;
return this;
@@ -746,7 +772,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
if (bankDetails.isEmpty() && debitDetails.isEmpty()) {
return null;
}
List<IZUGFeRDTradeSettlement> tradeSettlements = Stream.concat(bankDetails.stream(), debitDetails.stream()).map(IZUGFeRDTradeSettlement.class::cast).collect(Collectors.toList());
List<IZUGFeRDTradeSettlement> tradeSettlements = Stream.concat(bankDetails.stream(), debitDetails.stream()).collect(Collectors.toList());
IZUGFeRDTradeSettlement[] result = new IZUGFeRDTradeSettlement[tradeSettlements.size()];
for (int i = 0; i < tradeSettlements.size(); i++) {

View File

@@ -97,12 +97,12 @@ public class DAPullProvider extends ZUGFeRD2PullProvider {
+ XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "</ram:BuyerAssignedID>";
}
String allowanceChargeStr = "";
if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
if (currentItem.getItemAllowances() != null) {
for (final IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
allowanceChargeStr += getAllowanceChargeStr(allowance, currentItem);
}
}
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
if (currentItem.getItemCharges() != null) {
for (final IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
allowanceChargeStr += getAllowanceChargeStr(charge, currentItem);

View File

@@ -22,7 +22,7 @@ public class LineCalculator {
public LineCalculator(IZUGFeRDExportableItem currentItem) {
if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
if (currentItem.getItemAllowances() != null) {
for (IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
BigDecimal factor=BigDecimal.ONE;
BigDecimal singleAllowance=allowance.getTotalAmount(currentItem);
@@ -35,7 +35,7 @@ public class LineCalculator {
}
}
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
if (currentItem.getItemCharges() != null) {
for (IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
BigDecimal factor=BigDecimal.ONE;
BigDecimal singleCharge=charge.getTotalAmount(currentItem);
@@ -47,7 +47,7 @@ public class LineCalculator {
}
}
if (currentItem.getItemTotalAllowances() != null && currentItem.getItemTotalAllowances().length > 0) {
if (currentItem.getItemTotalAllowances() != null) {
for (final IZUGFeRDAllowanceCharge itemTotalAllowance : currentItem.getItemTotalAllowances()) {
addAllowanceItemTotal(itemTotalAllowance.getTotalAmount(currentItem));
}
@@ -94,7 +94,7 @@ public class LineCalculator {
? BigDecimal.ONE.setScale(4)
: currentItem.getBasisQuantity();
itemTotalNetAmount = quantity.multiply(price).divide(basisQuantity, 18, RoundingMode.HALF_UP)
.add(lineCharge).subtract(lineAllowance).subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
.add(lineCharge).subtract(lineAllowance).subtract(allowanceItemTotal.setScale(2, RoundingMode.HALF_UP)).setScale(2, RoundingMode.HALF_UP);
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);//.setScale(2, RoundingMode.HALF_UP);
}

View File

@@ -57,7 +57,7 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
paymentTermsDescription = XMLTools.encodeXML(trans.getPaymentTermDescription());
}
if ((paymentTermsDescription == null) && (trans.getDocumentCode() != CORRECTEDINVOICE)/* && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)*/) {
if (paymentTermsDescription == null && !CORRECTEDINVOICE.equals(trans.getDocumentCode())/* && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)*/) {
paymentTermsDescription = "Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate());
}
@@ -125,12 +125,12 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
+ XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "</ram:BuyerAssignedID>";
}
String allowanceChargeStr = "";
if (currentItem.getItemAllowances() != null && currentItem.getItemAllowances().length > 0) {
if (currentItem.getItemAllowances() != null) {
for (final IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
allowanceChargeStr += getAllowanceChargeStr(allowance, currentItem);
}
}
if (currentItem.getItemCharges() != null && currentItem.getItemCharges().length > 0) {
if (currentItem.getItemCharges() != null) {
for (final IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
allowanceChargeStr += getAllowanceChargeStr(charge, currentItem);
@@ -313,8 +313,9 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
for (final IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) {
if (payment != null) {
hasDueDate = true;
// xml += payment.getSettlementXML();
}
break;
// xml += payment.getSettlementXML();
}
}
}
if (trans.getTradeSettlement() != null) {

View File

@@ -89,7 +89,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
private BigDecimal sumAllowanceCharge(BigDecimal percent, IZUGFeRDAllowanceCharge[] charges) {
BigDecimal res = BigDecimal.ZERO;
if ((charges != null) && (charges.length > 0)) {
if (charges != null) {
for (IZUGFeRDAllowanceCharge currentCharge : charges) {
if ((percent == null) || (currentCharge.getTaxPercent().compareTo(percent) == 0)) {
res = res.add(currentCharge.getTotalAmount(this));
@@ -172,6 +172,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
* @return item sum +- charges/allowances
*/
public BigDecimal getTaxBasis() {
BigDecimal debug_1=getTotal();
return getTotal().add(getChargesForPercent(null).setScale(2, RoundingMode.HALF_UP))
.subtract(getAllowancesForPercent(null).setScale(2, RoundingMode.HALF_UP))
.setScale(2, RoundingMode.HALF_UP);
@@ -211,7 +212,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
IZUGFeRDAllowanceCharge[] charges = trans.getZFCharges();
if ((charges != null) && (charges.length > 0)) {
if (charges != null) {
for (IZUGFeRDAllowanceCharge currentCharge : charges) {
BigDecimal taxPercent = currentCharge.getTaxPercent();
if (taxPercent != null) {
@@ -229,7 +230,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
}
IZUGFeRDAllowanceCharge[] allowances = trans.getZFAllowances();
if ((allowances != null) && (allowances.length > 0)) {
if (allowances != null) {
for (IZUGFeRDAllowanceCharge currentAllowance : allowances) {
BigDecimal taxPercent = currentAllowance.getTaxPercent();
if (taxPercent != null) {
@@ -285,8 +286,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
final IZUGFeRDAllowanceCharge[] charges = this.trans.getZFCharges();
if (charges != null && charges.length > 0)
{
if (charges != null) {
for (final IZUGFeRDAllowanceCharge currentCharge : charges)
{
final BigDecimal taxPercent = currentCharge.getTaxPercent();
@@ -309,8 +309,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
}
final IZUGFeRDAllowanceCharge[] allowances = this.trans.getZFAllowances();
if (allowances != null && allowances.length > 0)
{
if (allowances != null) {
for (final IZUGFeRDAllowanceCharge currentAllowance : allowances)
{
final BigDecimal taxPercent = currentAllowance.getTaxPercent();

View File

@@ -4,6 +4,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
import org.mustangproject.XMLTools;
import org.slf4j.Logger;
@@ -18,7 +19,7 @@ public class XRechnungImporter extends ZUGFeRDImporter {
try {
setRawXML(rawXml);
containsMeta = true;
} catch (final IOException e) {
} catch (final IOException | ParseException e) {
LOGGER.error ("Failed to set raw XML", e);
throw new ZUGFeRDExportException(e);
}
@@ -30,24 +31,21 @@ public class XRechnungImporter extends ZUGFeRDImporter {
try {
setRawXML(Files.readAllBytes(Paths.get(filename)));
containsMeta = true;
} catch (final IOException e) {
LOGGER.error ("Failed to set raw XML", e);
} catch (final IOException | ParseException e) {
LOGGER.error ("Failed to set raw XML", e);
throw new ZUGFeRDExportException(e);
}
}
public XRechnungImporter(InputStream fileinput) {
super();
try {
setRawXML(XMLTools.getBytesFromStream(fileinput));
containsMeta = true;
} catch (final IOException e) {
LOGGER.error ("Failed to set raw XML", e);
} catch (final IOException | ParseException e) {
LOGGER.error ("Failed to set raw XML", e);
throw new ZUGFeRDExportException(e);
}
}

View File

@@ -359,7 +359,10 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
paymentTermsDescription += discount.getAsXRechnung();
}
} else if ((paymentTermsDescription == null) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CORRECTEDINVOICE) && (trans.getDocumentCode() != DocumentCodeTypeConstants.CREDITNOTE)) {
} else if (paymentTermsDescription == null
&& !DocumentCodeTypeConstants.CORRECTEDINVOICE.equals(trans.getDocumentCode())
&& !DocumentCodeTypeConstants.CREDITNOTE.equals(trans.getDocumentCode())
) {
if (trans.getDueDate() != null) {
paymentTermsDescription = "Please remit until " + germanDateFormat.format(trans.getDueDate());
}
@@ -434,11 +437,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
xml += "<ram:Name>" + XMLTools.encodeXML(currentItem.getProduct().getName()) + "</ram:Name>";
if (currentItem.getProduct().getDescription() != null && currentItem.getProduct().getDescription().length() > 0) {
if (currentItem.getProduct().getDescription() != null) {
xml += "<ram:Description>" +
XMLTools.encodeXML(currentItem.getProduct().getDescription()) +
"</ram:Description>";
}
if (currentItem.getProduct().getAttributes() != null) {
for (Entry<String, String> entry : currentItem.getProduct().getAttributes().entrySet()) {
xml += "<ram:ApplicableProductCharacteristic>" +
@@ -447,7 +451,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
"</ram:ApplicableProductCharacteristic>";
}
}
if (currentItem.getProduct().getClassifications() != null && currentItem.getProduct().getClassifications().length > 0) {
if (currentItem.getProduct().getClassifications() != null) {
for (IDesignatedProductClassification classification : currentItem.getProduct().getClassifications()) {
xml += "<ram:DesignatedProductClassification>"
+ "<ram:ClassCode listID=\"" + XMLTools.encodeXML(classification.getClassCode().getListID()) + "\"";
@@ -702,7 +706,9 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
}
}
if ((trans.getDocumentCode() == DocumentCodeTypeConstants.CORRECTEDINVOICE) || (trans.getDocumentCode() == DocumentCodeTypeConstants.CREDITNOTE)) {
if (DocumentCodeTypeConstants.CORRECTEDINVOICE.equals(trans.getDocumentCode())
|| DocumentCodeTypeConstants.CREDITNOTE.equals(trans.getDocumentCode())
) {
hasDueDate = false;
}
@@ -857,7 +863,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
} else {
xml += buildPaymentTermsXml();
}
if ((profile == Profiles.getByName("Extended")) && (trans.getCashDiscounts() != null) && (trans.getCashDiscounts().length > 0)) {
if (profile == Profiles.getByName("Extended") && trans.getCashDiscounts() != null) {
for (IZUGFeRDCashDiscount discount : trans.getCashDiscounts()
) {
xml += discount.getAsCII();

View File

@@ -564,10 +564,9 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
// iterate over all pdf pages
for (Object object : doc.getPages()) {
if (object instanceof PDPage) {
for (PDPage page : doc.getPages()) {
if (page != null) {
PDPage page = (PDPage) object;
PDResources res = page.getResources();
// Check for fonts in PDXObjects:

View File

@@ -14,6 +14,7 @@ package org.mustangproject.ZUGFeRD;
* @author jstaerk
*/
import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -351,6 +352,16 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter {
public String getHolder() {
if (importedInvoice!=null && importedInvoice.getTradeSettlement()!=null) {
for (IZUGFeRDTradeSettlement settlement : importedInvoice.getTradeSettlement()) {
if (settlement instanceof IZUGFeRDTradeSettlementPayment) {
String s = ((IZUGFeRDTradeSettlementPayment) settlement).getAccountName();
if ( s != null ) {
return s;
}
}
}
}
return extractString("//*[local-name() = 'SellerTradeParty']/*[local-name() = 'Name']");
}
@@ -452,7 +463,11 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter {
* @throws IOException if raw can not be set
*/
public void setMeta(String meta) throws IOException {
setRawXML(meta.getBytes());
try {
setRawXML(meta.getBytes());
} catch (ParseException e) {
LOGGER.error("Failed to parse", e);
}
}

View File

@@ -10,7 +10,6 @@ import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
import org.mustangproject.*;
import org.mustangproject.Exceptions.ArithmetricException;
import org.mustangproject.Exceptions.StructureException;
import org.mustangproject.util.NodeMap;
import org.slf4j.Logger;
@@ -127,8 +126,7 @@ public class ZUGFeRDInvoiceImporter {
if (Arrays.equals(pad, pdfSignature)) { // we have a pdf
try {
PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(pdfStream));
try(PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(pdfStream))) {
// PDDocumentInformation info = doc.getDocumentInformation();
final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
//start
@@ -174,7 +172,12 @@ public class ZUGFeRDInvoiceImporter {
} else {
// no PDF probably XML
containsMeta = true;
setRawXML(XMLTools.getBytesFromStream(pdfStream));
try {
setRawXML(XMLTools.getBytesFromStream(pdfStream));
} catch(ParseException e) {
LOGGER.error("Failed to parse PDF", e);
}
}
}
@@ -209,7 +212,16 @@ public class ZUGFeRDInvoiceImporter {
*/
final PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml")) || filename.equals("xrechnung.xml") || filename.equals("order-x.xml") || filename.equals("cida.xml")) {
Set<String> validFilenames = Set.of(
"ZUGFeRD-invoice.xml",
"zugferd-invoice.xml",
"factur-x.xml",
"xrechnung.xml",
"order-x.xml",
"cida.xml"
);
if (validFilenames.contains(filename)) {
containsMeta = true;
// String embeddedFilename = filePath + filename;
@@ -219,8 +231,11 @@ public class ZUGFeRDInvoiceImporter {
// ByteArrayOutputStream();
// FileOutputStream fos = new FileOutputStream(file);
setRawXML(embeddedFile.toByteArray());
try {
setRawXML(embeddedFile.toByteArray());
} catch (ParseException e) {
LOGGER.error("Failed to parse XML", e);
}
// fos.write(embeddedFile.getByteArray());
// fos.close();
}
@@ -237,7 +252,7 @@ public class ZUGFeRDInvoiceImporter {
* @param doParse automatically parse input for zugferdImporter (not ZUGFeRDInvoiceImporter)
* @throws IOException if parsing xml throws it (unlikely its string based)
*/
public void setRawXML(byte[] rawXML, boolean doParse) throws IOException {
public void setRawXML(byte[] rawXML, boolean doParse) throws IOException, ParseException {
this.containsMeta = true;
this.rawXML = rawXML;
this.version = null;
@@ -245,7 +260,7 @@ public class ZUGFeRDInvoiceImporter {
try {
setDocument();
} catch (ParserConfigurationException | SAXException | ParseException e) {
} catch (ParserConfigurationException | SAXException e) {
LOGGER.error("Failed to parse XML", e);
throw new ZUGFeRDExportException(e);
}
@@ -257,7 +272,7 @@ public class ZUGFeRDInvoiceImporter {
* @param rawXML the cii(?) as a string
* @throws IOException if parsing xml throws it (unlikely its string based)
*/
public void setRawXML(byte[] rawXML) throws IOException {
public void setRawXML(byte[] rawXML) throws IOException, ParseException {
setRawXML(rawXML, true);
}
@@ -353,39 +368,31 @@ public class ZUGFeRDInvoiceImporter {
delivery.addGlobalID(sID);
}
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("StreetName").ifPresent(t -> delivery.setStreet(t));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("AdditionalStreetName").ifPresent(t -> delivery.setAdditionalAddress(t));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("CityName").ifPresent(t -> delivery.setLocation(t));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("PostalZone").ifPresent(t -> delivery.setZIP(t));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsNodeMap("Country").ifPresent(t -> t.getAsString("IdentificationCode").ifPresent(u -> delivery.setCountry(u)));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsNodeMap("AddressLine").ifPresent(t -> t.getAsString("Line").ifPresent(u -> delivery.setAdditionalAddressExtension(u)));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("AdditionalStreetName").ifPresent(t -> delivery.setAdditionalAddress(t));
});
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
s.getAsString("AdditionalStreetName").ifPresent(t -> delivery.setAdditionalAddress(t));
});
Optional<NodeMap> addressNodeMapp = deliveryLocationNodeMap.getAsNodeMap("Address");
addressNodeMapp.flatMap(s -> s.getAsString("StreetName"))
.ifPresent(delivery::setStreet);
addressNodeMapp.flatMap(s -> s.getAsString("AdditionalStreetName"))
.ifPresent(delivery::setAdditionalAddress);
addressNodeMapp.flatMap(s -> s.getAsString("CityName"))
.ifPresent(delivery::setLocation);
addressNodeMapp.flatMap(s -> s.getAsString("PostalZone"))
.ifPresent(delivery::setZIP);
addressNodeMapp.flatMap(s -> s.getAsNodeMap("Country")).flatMap(t -> t.getAsString("IdentificationCode"))
.ifPresent(delivery::setCountry);
addressNodeMapp.flatMap(s -> s.getAsNodeMap("AddressLine")).flatMap(t -> t.getAsString("Line"))
.ifPresent(delivery::setAdditionalAddressExtension);
addressNodeMapp.flatMap(s -> s.getAsString("AdditionalStreetName"))
.ifPresent(delivery::setAdditionalAddress);
addressNodeMapp.flatMap(s -> s.getAsString("AdditionalStreetName"))
.ifPresent(delivery::setAdditionalAddress);
});
new NodeMap(deliveryNode).getAsNodeMap("DeliveryParty").ifPresent(partyMap -> {
partyMap.getAsNodeMap("PartyName").ifPresent(s -> {
s.getAsString("Name").ifPresent(t -> delivery.setName(t));
});
});
String street, name, additionalStreet, city, postal, countrySubentity, line, country = null;
new NodeMap(deliveryNode).getAsNodeMap("DeliveryParty")
.flatMap(partyMap -> partyMap.getAsNodeMap("PartyName"))
.flatMap(s -> s.getAsString("Name"))
.ifPresent(delivery::setName);
zpp.setDeliveryAddress(delivery);
}
@@ -424,7 +431,7 @@ public class ZUGFeRDInvoiceImporter {
xpr = xpath.compile("//*[local-name()=\"ExchangedDocument\"]|//*[local-name()=\"HeaderExchangedDocument\"]");
NodeList ExchangedDocumentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
xpr = xpath.compile("//*[local-name()=\"GrandTotalAmount\"]|//*[local-name()=\"TaxInclusiveAmount\"]");
BigDecimal expectedGrandTotal = null;
NodeList totalNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
@@ -572,11 +579,11 @@ public class ZUGFeRDInvoiceImporter {
}
String creditorReferenceID = extractString("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"CreditorReferenceID\"]").trim();//BT-90
if ((creditorReferenceID == null)||(creditorReferenceID.length()==0)) {
if (creditorReferenceID == null || creditorReferenceID.isEmpty()) {
//maybe it's there in UBL?
creditorReferenceID = extractString("//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyIdentification\"]/*[local-name()=\"ID\"]").trim();
}
if ((creditorReferenceID != null)&&(creditorReferenceID.length()>0)) {
if (creditorReferenceID != null && !creditorReferenceID.isEmpty()) {
zpp.setCreditorReferenceID(creditorReferenceID);
}
@@ -1088,7 +1095,7 @@ public class ZUGFeRDInvoiceImporter {
.collect(Collectors.joining(" + "));
} catch (Exception ignored) {
}
throw new ArithmetricException("Payable total in XML is " + payableTotalFromXml + ", but calculated total is " + calculatedPayableTotal + moreDetails);
throw new ArithmeticException("Payable total in XML is " + payableTotalFromXml + ", but calculated total is " + calculatedPayableTotal + moreDetails);
}
}
}
@@ -1205,7 +1212,7 @@ public class ZUGFeRDInvoiceImporter {
* sets the XML for the importer to parse
* @param XML the UBL or CII
*/
public void fromXML(String XML) {
public void fromXML(String XML) throws ParseException{
try {
containsMeta = true;
setRawXML(XML.getBytes(StandardCharsets.UTF_8));

View File

@@ -12,12 +12,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.xpath.XPathExpressionException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.*;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/***
* tests the linecalculator and transactioncalculator classes
@@ -79,6 +78,56 @@ public class CalculationTest extends ResourceCase {
assertEquals(valueOf(287.9408).stripTrailingZeros(), calculator.getItemTotalVATAmount().stripTrailingZeros());
}
@Test
public void testAllowanceAndChargeEx4() {
/** numbers from en16931 example 4 */
SimpleDateFormat sqlDate = new SimpleDateFormat("yyyy-MM-dd");
Invoice invoice = new Invoice();
invoice.setDocumentName("Rechnung");
invoice.setNumber("777777");
try {
invoice.setIssueDate(sqlDate.parse("2020-12-31"));
} catch (Exception e) {
LOGGER.error("Failed to set dates", e);
}
/* trade party (sender) */
TradeParty sender = new TradeParty("Maier GmbH", "Musterweg 5", "11111", "Testung", "DE");
sender.addVATID("DE2222222222");
invoice.setSender(sender);
/* trade party (recipient) */
TradeParty recipient = new TradeParty("Teston GmbH" + " " + "Zentrale" + " " + "", "Testweg 5", "11111", "Testung", "DE");
invoice.setRecipient(recipient);
/* item */
Product product;
Item item;
product = new Product("Pens", "", "H87", new BigDecimal(25));
product.addAllowance(new Allowance(new BigDecimal(1)));
item = new Item(product, new BigDecimal("9.50"), new BigDecimal(25));
item.addCharge(new Charge(new BigDecimal(10)).setReasonCode("ZZZ").setReason("Zuschlag"));
LineCalculator lc = new LineCalculator(item);
assertEquals(new BigDecimal("222.50"), lc.getItemTotalNetAmount());
invoice.addItem(item);
product = new Product("Paper", "", "H87", new BigDecimal(25));
item = new Item(product, new BigDecimal("4.50"), new BigDecimal(15));
item.addAllowance(new Allowance().setPercent(new BigDecimal(5)).setReasonCode("ZZZ").setReason("Zuschlag"));
lc = new LineCalculator(item);
assertEquals(new BigDecimal("64.12"), lc.getItemTotalNetAmount());
invoice.addItem(item);
invoice.addAllowance(new Allowance().setPercent(new BigDecimal(10)).setTaxPercent(new BigDecimal(25)).setReasonCode("ZZZ").setReason("Mengenrabatt"));
invoice.addCharge(new Charge(new BigDecimal(15)).setReasonCode("ZZZ").setReason("Frachtkosten"));
TransactionCalculator calculator = new TransactionCalculator(invoice);
assertEquals(valueOf(286.62).stripTrailingZeros(), calculator.getTotal());// interestingly, EN16931-1 has 286.63 here?
assertEquals(valueOf(272.96).stripTrailingZeros(), calculator.getTaxBasis()); // and 272.97 here
assertEquals(valueOf(337.45).stripTrailingZeros(), calculator.getDuePayable()); // and 337.46 here???
}
@Test
public void testLineCalculatorForeignCurrencyExample() {
/*** xml of official fx sample with allowances and charges
@@ -88,19 +137,19 @@ public class CalculationTest extends ResourceCase {
*/
File inputCII = getResourceAsFile("Extended_fremdwaehrung.xml");
ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter();
Invoice invoice=null;
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
Invoice invoice = null;
zii.doIgnoreCalculationErrors();
boolean hasExceptions=false;
boolean hasExceptions = false;
try {
zii.setInputStream(new FileInputStream(inputCII));
invoice=zii.extractInvoice();
invoice = zii.extractInvoice();
} catch (XPathExpressionException | ParseException e) {
// handle Exceptions
hasExceptions=true;
hasExceptions = true;
} catch (FileNotFoundException e) {
hasExceptions=true;
hasExceptions = true;
}
assertFalse(hasExceptions);
// Reading ZUGFeRD
@@ -152,7 +201,7 @@ public class CalculationTest extends ResourceCase {
Product product;
Item item;
product = new Product("AAA", "", "H84", sales_tax_percent1).setSellerAssignedID("1AAA");
product = new Product("AAA", "", "H87", sales_tax_percent1).setSellerAssignedID("1AAA");
item = new Item(product, new BigDecimal("4.750"), new BigDecimal(5.00));
// set values for additional charge and discount used for next lines
@@ -168,54 +217,23 @@ public class CalculationTest extends ResourceCase {
}
invoice.addItem(item);
// reset values for additional charge and discount used for next lines
item_increase = BigDecimal.ZERO;
item_discount = BigDecimal.ZERO;
product = new Product("BBB", "", "H84", sales_tax_percent1).setSellerAssignedID("2BBB");
product = new Product("BBB", "", "H87", sales_tax_percent1).setSellerAssignedID("2BBB");
item = new Item(product, new BigDecimal("5.750"), new BigDecimal(4.00));
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
}
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
}
invoice.addItem(item);
product = new Product("CCC", "", "H84", sales_tax_percent1).setSellerAssignedID("3CCC");
product = new Product("CCC", "", "H87", sales_tax_percent1).setSellerAssignedID("3CCC");
item = new Item(product, new BigDecimal("6.750"), new BigDecimal(3.00));
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
}
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
}
invoice.addItem(item);
product = new Product("DDD", "", "H84", sales_tax_percent1).setSellerAssignedID("4DDD");
product = new Product("DDD", "", "H87", sales_tax_percent1).setSellerAssignedID("4DDD");
item = new Item(product, new BigDecimal("7.750"), new BigDecimal(2.00));
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
}
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
}
invoice.addItem(item);
product = new Product("EEE", "", "H84", sales_tax_percent1).setSellerAssignedID("5EEE");
product = new Product("EEE", "", "H87", sales_tax_percent1).setSellerAssignedID("5EEE");
item = new Item(product, new BigDecimal("8.750"), new BigDecimal(1.00));
if (item_increase.compareTo(BigDecimal.ZERO) > 0) {
item.addCharge(new Charge().setPercent(item_increase).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschlag"));
}
if (item_discount.compareTo(BigDecimal.ZERO) > 0) {
item.addAllowance(new Allowance().setPercent(item_discount).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatt"));
}
invoice.addItem(item);
// reset values for additional charge and discount used on invoice level
item_increase = BigDecimal.valueOf(3.50);
item_discount = BigDecimal.valueOf(10.00);
if (total_increase_percent.compareTo(BigDecimal.ZERO) > 0) {
invoice.addCharge(new Charge().setPercent(total_increase_percent).setTaxPercent(sales_tax_percent1).setReasonCode("ZZZ").setReason("Zuschläge"));
@@ -224,7 +242,7 @@ public class CalculationTest extends ResourceCase {
invoice.addAllowance(new Allowance().setPercent(total_discount_percent).setTaxPercent(sales_tax_percent1).setReasonCode("95").setReason("Rabatte"));
}
TransactionCalculator calculator = new TransactionCalculator(invoice);
assertEquals(valueOf(307.18).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros());
assertEquals(valueOf(101.85).stripTrailingZeros(), calculator.getGrandTotal().stripTrailingZeros());
}
public void testSimpleItemPercentAllowance() {
@@ -259,14 +277,64 @@ public class CalculationTest extends ResourceCase {
Product product;
Item item;
product = new Product("AAA", "", "H84", BigDecimal.ZERO);
product = new Product("AAA", "", "H87", BigDecimal.ZERO);
item = new Item(product, new BigDecimal("1.10"), new BigDecimal(5.00));
item.addAllowance(new Allowance().setPercent(new BigDecimal(10)).setTaxPercent(BigDecimal.ZERO));
invoice.addItem(item);
TransactionCalculator calculator = new TransactionCalculator(invoice);
assertEquals(new BigDecimal(5), calculator.getGrandTotal().stripTrailingZeros());
assertEquals(new BigDecimal("4.95"), calculator.getGrandTotal().stripTrailingZeros());
}
public void testSimpleDocumentPercentCharge() {
String orgname = "Test company";
String number = "123";
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
// similar, but slightly less complicated to whats later testted in testRelativeChargesAllowancesExport
Invoice i = new Invoice().setCurrency("CHF").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815"))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addCharge(new Charge().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK"));
// 9+50%=>13,50 expected net
// .addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReason("Mengenrabatt"))
TransactionCalculator tc = new TransactionCalculator(i);
assertEquals(new BigDecimal("13.50"), tc.getTaxBasis());
assertEquals(new BigDecimal("16.07"), tc.getDuePayable());
}
public void testSimpleDocumentPercentAllowance() {
String orgname = "Test company";
String number = "123";
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
// similar, but slightly less complicated to whats later testted in testRelativeChargesAllowancesExport
Invoice i = new Invoice().setCurrency("CHF").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815"))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK"));
// 9-50%=>4,50 expected net
// .addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReason("Mengenrabatt"))
TransactionCalculator tc = new TransactionCalculator(i);
assertEquals(new BigDecimal("4.50"), tc.getTaxBasis());
assertEquals(new BigDecimal("5.36"), tc.getDuePayable());
}
public void testSimpleItemTotalAllowance() {
@@ -301,7 +369,7 @@ public class CalculationTest extends ResourceCase {
Product product;
Item item;
product = new Product("AAA", "", "H84", BigDecimal.ZERO);
product = new Product("AAA", "", "H87", BigDecimal.ZERO);
item = new Item(product, new BigDecimal("1.00"), new BigDecimal(5.00));
item.addAllowance(new Allowance(new BigDecimal(1)).setTaxPercent(BigDecimal.ZERO));
@@ -314,7 +382,7 @@ public class CalculationTest extends ResourceCase {
/**
* LineCalculator should not throw an exception when calculating a non-terminating decimal expansion
* */
*/
@Test
public void testNonTerminatingDecimalExpansion() {
final Product product = new Product();

View File

@@ -21,6 +21,13 @@
*/
package org.mustangproject.ZUGFeRD;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import org.mustangproject.*;
import org.mustangproject.ZUGFeRD.model.EventTimeCodeTypeConstants;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
@@ -29,28 +36,11 @@ import java.nio.file.Files;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import javax.xml.xpath.XPathExpressionException;
import org.junit.FixMethodOrder;
import org.junit.experimental.theories.FromDataPoints;
import org.junit.runners.MethodSorters;
import org.mustangproject.Allowance;
import org.mustangproject.BankDetails;
import org.mustangproject.CalculatedInvoice;
import org.mustangproject.CashDiscount;
import org.mustangproject.Charge;
import org.mustangproject.Contact;
import org.mustangproject.Invoice;
import org.mustangproject.Item;
import org.mustangproject.Product;
import org.mustangproject.SchemedID;
import org.mustangproject.TradeParty;
import org.mustangproject.ZUGFeRD.model.EventTimeCodeTypeConstants;
import static org.assertj.core.api.Assertions.assertThat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class DeSerializationTest extends ResourceCase {
@@ -71,6 +61,29 @@ public class DeSerializationTest extends ResourceCase {
}
public void testProduct() throws IOException, XPathExpressionException, ParseException {
File inputCII = getResourceAsFile("Extended_fremdwaehrung.xml");
var zii = new ZUGFeRDInvoiceImporter();
zii.doIgnoreCalculationErrors();
zii.fromXML(Files.readString(inputCII.toPath()));
var product = zii.extractInvoice()
.getZFItems()[0]
.getProduct();
assertThat(product.getCountryOfOrigin()).as("Product Country of origin")
.isEqualTo("DE");
assertThat(product.getSellerAssignedID()).as("Product Seller assigned ID")
.isEqualTo("CO-123/V2A");
assertThat(product.getBuyerAssignedID()).as("Product Buyer assigned ID")
.isEqualTo("Toolbox 0815");
assertThat(product.getName()).as("Name")
.isEqualTo("Stahlcoil");
assertThat(product.getAttributes()).as("Product attributes")
.containsKey("LeoID")
.containsValue("704310.0105636504");
}
public void testInvoiceLine() throws JsonProcessingException {
File inputCII = getResourceAsFile("factur-x.xml");
boolean hasExceptions = false;
@@ -79,7 +92,7 @@ public class DeSerializationTest extends ResourceCase {
try {
zii.fromXML(new String(Files.readAllBytes(inputCII.toPath()), StandardCharsets.UTF_8));
} catch (IOException e) {
} catch (IOException | ParseException e) {
hasExceptions = true;
}
@@ -395,7 +408,7 @@ public class DeSerializationTest extends ResourceCase {
try {
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
TransactionCalculator tc=new TransactionCalculator(newInvoiceFromJSON);
assertEquals(new BigDecimal("18.92"),tc.getGrandTotal());
assertEquals(new BigDecimal("18.33"),tc.getGrandTotal());
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
@@ -414,10 +427,12 @@ public class DeSerializationTest extends ResourceCase {
String number = "123";
String priceStr = "1.00";
String taxID = "9990815";
BigDecimal price = new BigDecimal(priceStr);
Invoice newInvoiceFromJSON = null;
boolean hasExceptions = false;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String json = "";
try {
SchemedID gtin = new SchemedID("0160", "2001015001325");
SchemedID gln = new SchemedID("0088", "4304171000002");
@@ -435,7 +450,7 @@ public class DeSerializationTest extends ResourceCase {
.addCashDiscount(new CashDiscount(new BigDecimal(2), 14))
.setDeliveryDate(sdf.parse("2020-11-02")).setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE);
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(i);
json = mapper.writeValueAsString(i);
newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
} catch (ParseException e) {
hasExceptions = true;
@@ -444,8 +459,34 @@ public class DeSerializationTest extends ResourceCase {
}
assertEquals(newInvoiceFromJSON.getBuyerOrderReferencedDocumentID(), "28934");
assertFalse(hasExceptions);
}
public void testFromJSON() throws JsonProcessingException {
String globalID = "4000001123452";
String globalIDScheme = "0088";
String itemDeliveryFrom="2022-01-28T23:00:00.000+00:00";
String itemDeliveryTo="2022-01-30T23:00:00.000+00:00";
String json="{\"number\":\"123\",\"buyerOrderReferencedDocumentID\":\"28934\",\"currency\":\"CHF\",\"issueDate\":1752744199178,\"dueDate\":1752744199178,\"deliveryDate\":1604271600000,\"sender\":{\"name\":\"Test company\",\"zip\":\"55232\",\"street\":\"teststr\",\"location\":\"teststadt\",\"country\":\"DE\",\"taxID\":\"9990815\",\"vatID\":\"DE0815\",\"id\":\"0009845\",\"globalID\":\""+globalID+"\",\"globalIDScheme\":\""+globalIDScheme+"\",\"email\":\"sender@test.org\",\"vatid\":\"DE0815\"},\"recipient\":{\"name\":\"Franz Müller\",\"zip\":\"55232\",\"street\":\"teststr.12\",\"location\":\"Entenhausen\",\"country\":\"DE\",\"vatID\":\"DE4711\",\"additionalAddress\":\"Hinterhaus 3\",\"contact\":{\"name\":\"Franz Müller\",\"phone\":\"01779999999\",\"email\":\"franz@mueller.de\",\"zip\":\"55232\",\"street\":\"teststr. 12\",\"location\":\"Entenhausen\",\"country\":\"DE\",\"fax\":\"++49555123456\"},\"globalID\":\"4304171000002\",\"globalIDScheme\":\"0088\",\"email\":\"recipient@test.org\",\"vatid\":\"DE4711\"},\"deliveryAddress\":{\"name\":\"just the other side of the street\",\"zip\":\"55232\",\"street\":\"teststr.12a\",\"location\":\"Entenhausen\",\"country\":\"DE\",\"vatID\":\"DE47110\",\"vatid\":\"DE47110\"},\"cashDiscounts\":[{\"percent\":2,\"days\":14}],\"notes\":[\"document level 1/2\",\"document level 2/2\"],\"sellerOrderReferencedDocumentID\":\"9384\",\"contractReferencedDocument\":\"376zreurzu0983\",\"valid\":true,\"vatdueDateTypeCode\":\"72\",\"zfitems\":[{\"price\":1.00,\"quantity\":1,\"basisQuantity\":1,\"detailedDeliveryPeriodFrom\":\""+itemDeliveryFrom+"\",\"detailedDeliveryPeriodTo\":\""+itemDeliveryTo+"\",\"id\":\"a123\",\"buyerOrderReferencedDocumentLineID\":\"xxx\",\"product\":{\"unit\":\"H87\",\"name\":\"Testprodukt\",\"sellerAssignedID\":\"4711\",\"taxCategoryCode\":\"S\",\"globalID\":\"2001015001325\",\"globalIDScheme\":\"0160\",\"intraCommunitySupply\":false,\"reverseCharge\":false,\"vatpercent\":16},\"notes\":[\"item level 1/1\"],\"notesWithSubjectCode\":[{\"content\":\"item level 1/1\"}],\"itemAllowances\":[{\"totalAmount\":0.0200000000000000004163336342344337026588618755340576171875,\"taxPercent\":16,\"reason\":\"item discount\",\"categoryCode\":\"S\"}],\"value\":1.00}],\"ownVATID\":\"DE0815\",\"detailedDeliveryPeriodFrom\":1601503200000,\"detailedDeliveryPeriodTo\":1601848800000,\"ownTaxID\":\"9990815\",\"ownZIP\":\"55232\",\"ownLocation\":\"teststadt\",\"zfallowances\":[{\"totalAmount\":0.200000000000000011102230246251565404236316680908203125,\"taxPercent\":16,\"reason\":\"discount\",\"categoryCode\":\"S\"}],\"ownStreet\":\"teststr\",\"zfcharges\":[{\"totalAmount\":0.5,\"taxPercent\":16,\"reason\":\"quick delivery charge\",\"categoryCode\":\"S\"}],\"ownCountry\":\"DE\"}";
ObjectMapper mapper = new ObjectMapper();
Invoice fromJSON = mapper.readValue(json, Invoice.class);
assertEquals(globalID, fromJSON.getSender().getGlobalID());
assertEquals(globalIDScheme, fromJSON.getSender().getGlobalIDScheme());
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
assertEquals("2022-01-28", sdf.format(fromJSON.getZFItems()[0].getDetailedDeliveryPeriodFrom()));
assertEquals("2022-01-30", sdf.format(fromJSON.getZFItems()[0].getDetailedDeliveryPeriodTo()));
assertEquals("sender@test.org", fromJSON.getSender().getEmail());
}
public void testGrossFromJSON() throws JsonProcessingException {
String json="{ \"documentCode\": \"380\", \"number\": \"123\", \"currency\": \"EUR\", \"paymentTermDescription\": \"Please remit until 28.07.2025\", \"issueDate\": 1753653600000, \"dueDate\": 1753653600000, \"sender\": { \"name\": \"Test company\", \"zip\": \"55232\", \"street\": \"teststr\", \"location\": \"teststadt\", \"country\": \"DE\", \"taxID\": \"4711\", \"vatID\": \"DE0815\", \"vatid\": \"DE0815\" }, \"recipient\": { \"name\": \"Franz Müller\", \"zip\": \"55232\", \"street\": \"teststr.12\", \"location\": \"Entenhausen\", \"country\": \"DE\", \"contact\": { \"name\": \"contact testname\", \"phone\": \"123456\", \"email\": \"contact.testemail@example.org\", \"fax\": \"0911623562\" } }, \"totalPrepaidAmount\": 0.00, \"lineTotalAmount\": 29.00, \"duePayable\": 34.51, \"grandTotal\": 34.51, \"taxBasis\": 29.00, \"valid\": true, \"zfitems\": [ { \"price\": 3.0000, \"quantity\": 10.0000, \"basisQuantity\": 1.0000, \"id\": \"1\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"allowances\": [ { \"totalAmount\": 0.1000, \"categoryCode\": \"S\" } ], \"vatpercent\": 19.00, \"intraCommunitySupply\": false, \"reverseCharge\": false }, \"value\": 3.0000 } ], \"ownVATID\": \"DE0815\", \"ownTaxID\": \"4711\", \"ownLocation\": \"teststadt\", \"ownZIP\": \"55232\", \"ownCountry\": \"DE\", \"ownStreet\": \"teststr\"}";
ObjectMapper mapper = new ObjectMapper();
CalculatedInvoice fromJSON = mapper.readValue(json, CalculatedInvoice.class);
fromJSON.calculate();
assertEquals(new BigDecimal("34.51"),fromJSON.getDuePayable());
}
public void testDueDateRoundtrip() throws JsonProcessingException {

View File

@@ -189,8 +189,7 @@ public class XRTest extends TestCase {
zf2p.setProfile(Profiles.getByName("XRechnung"));
zf2p.generateXML(i);
final String xmlGen = new String(zf2p.getXML());
System.out.println(xmlGen);
final Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new ByteArrayInputStream(zf2p.getXML()));

View File

@@ -53,6 +53,7 @@ public class ZF2PushTest extends TestCase {
final String TARGET_ALLOWANCESPDF = "./target/testout-ZF2PushAllowances.pdf";
final String TARGET_CREDITNOTEPDF = "./target/testout-ZF2PushCreditNote.pdf";
final String TARGET_CORRECTIONPDF = "./target/testout-ZF2PushCorrection.pdf";
final String TARGET_ITEMGROSS = "./target/testout-ZF2PushGross.pdf";
final String TARGET_ITEMCHARGESALLOWANCESPDF = "./target/testout-ZF2PushItemChargesAllowances.pdf";
final String TARGET_CHARGESALLOWANCESPDF = "./target/testout-ZF2PushChargesAllowances.pdf";
final String TARGET_RELATIVECHARGESALLOWANCESPDF = "./target/testout-ZF2PushRelativeChargesAllowances.pdf";
@@ -114,8 +115,8 @@ public class ZF2PushTest extends TestCase {
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF);
assertTrue(zi.getUTF8().contains("DE88200800000970375700")); //the iban
assertTrue(zi.getUTF8().contains("Max Mustermann")); //account holder
assertTrue(zi.getUTF8().contains("DueDateDateTime")); //account holder
assertTrue(zi.getUTF8().contains("20201212")); //account holder
assertTrue(zi.getUTF8().contains("DueDateDateTime"));
assertTrue(zi.getUTF8().contains("20201212"));
assertTrue(zi.getUTF8().contains("<rsm:CrossIndustryInvoice"));
@@ -124,7 +125,7 @@ public class ZF2PushTest extends TestCase {
// Reading ZUGFeRD
assertEquals("571.04", zi.getAmount());
assertEquals(orgname, zi.getHolder());
assertEquals("Max Mustermann", zi.getHolder());
assertEquals(number, zi.getForeignReference());
try {
assertEquals(zi.getVersion(), 2);
@@ -159,7 +160,7 @@ public class ZF2PushTest extends TestCase {
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711")
.setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE")))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(0)).setTaxExemptionReason("Kleinunternehmer gemäß §19 UStG").setTaxCategoryCode("E"), price, new BigDecimal(1.0)).addNote(theNote))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(0)).setTaxExemptionReason("Kleinunternehmer gemäß §19 UStG").setTaxCategoryCode("E"), price, new BigDecimal(1.0)).addNote(theNote))
);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
@@ -219,7 +220,7 @@ public class ZF2PushTest extends TestCase {
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711")
.setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE")))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
);
String theXML = new String(ze.getProvider().getXML());
Invoice read = new Invoice();
@@ -237,13 +238,12 @@ public class ZF2PushTest extends TestCase {
fail("ParseException should not be raised");
}
}
public void testItemChargesAllowancesExport() {
public void testGross() {
String orgname = "Test company";
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
@@ -253,7 +253,71 @@ public class ZF2PushTest extends TestCase {
ze.setProducer("My Application").setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("extended");
// ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname,"teststr", "55232","teststadt","DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number)
// .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
// .addItem(new Item(new Product("Testprodukt", "", "H84", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
BigDecimal qty=new BigDecimal(10.0);
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date())
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815"))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")
.setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562")))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).addAllowance(new Allowance(new BigDecimal("0.1"))), price, qty));
ze.setTransaction(i);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
ze.export(TARGET_ITEMGROSS);
} catch (IOException e) {
fail("IOException should not be raised");
}
try {
// now check the contents (like MustangReaderTest)
ZUGFeRDInvoiceImporter zi = new ZUGFeRDInvoiceImporter(TARGET_ITEMGROSS);
CalculatedInvoice ci=new CalculatedInvoice();
zi.extractInto(ci);
assertThat(zi.getUTF8()).valueByXPath("//*[local-name()=\"GrossPriceProductTradePrice\"]/*[local-name()=\"ChargeAmount\"]")
.asString()
.isEqualTo("3.0000");
assertThat(zi.getUTF8()).valueByXPath("//*[local-name()=\"NetPriceProductTradePrice\"]/*[local-name()=\"ChargeAmount\"]")
.asString()
.isEqualTo("2.9000");
assertEquals("EUR", ci.getCurrency());
assertTrue(zi.getUTF8().contains("0911623562")); // fax number
ObjectMapper mapper = new ObjectMapper();
String jsonArray = mapper.writeValueAsString(ci);
// Reading ZUGFeRD
assertEquals(new BigDecimal("34.51"), ci.getDuePayable());
} catch (Exception e) {
fail("Exception should not be raised");
}
}
public void testItemChargesAllowancesExport() {
String orgname = "Test company";
String number = "123";
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1();
ze.ignorePDFAErrors().load(SOURCE_PDF);
ze.setProfile(Profiles.getByName("Extended"));
ze.setProducer("My Application").setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("extended");
// ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname,"teststr", "55232","teststadt","DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number)
// .addItem(new Item(new Product("Testprodukt", "", "H84", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date())
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815"))
@@ -261,10 +325,10 @@ public class ZF2PushTest extends TestCase {
.setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562")))
.setNumber(number)
.addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("AReason").setTaxPercent(new BigDecimal(19)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1")).setReasonCode("95")))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)).setReason("In love with salesperson")))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("AnotherReason")))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("Yet another reason")).addAllowance(new Allowance(new BigDecimal("1")).setReason("Something completely strange")));
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1")).setReasonCode("95")))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)).setReason("In love with salesperson")))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("AnotherReason")))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("Yet another reason")).addAllowance(new Allowance(new BigDecimal("1")).setReason("Something completely strange")));
ze.setTransaction(i);
@@ -283,7 +347,7 @@ public class ZF2PushTest extends TestCase {
assertTrue(zi.getUTF8().contains("ABK"));
// Reading ZUGFeRD
assertEquals("18.92", zi.getAmount());
assertEquals("18.33", zi.getAmount());
assertEquals(orgname, zi.getHolder());
assertEquals(number, zi.getForeignReference());
assertEquals(zi.getVersion(), 2);
@@ -300,8 +364,8 @@ public class ZF2PushTest extends TestCase {
String orgname = "Test company";
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
@@ -309,7 +373,7 @@ public class ZF2PushTest extends TestCase {
ze.ignorePDFAErrors().load(SOURCE_PDF);
ze.setProducer("My Application").setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("extended");
// ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname,"teststr", "55232","teststadt","DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number)
// .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
// .addItem(new Item(new Product("Testprodukt", "", "H84", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addVATID("DE0815").addTaxID("4711"))
@@ -317,10 +381,10 @@ public class ZF2PushTest extends TestCase {
.setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562")))
.setDeliveryAddress(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0816"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setIntraCommunitySupply(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setIntraCommunitySupply(), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setIntraCommunitySupply(), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setIntraCommunitySupply(), price, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setIntraCommunitySupply(), price, new BigDecimal(1.0)))
);
String theXML = new String(ze.getProvider().getXML());
@@ -373,7 +437,7 @@ public class ZF2PushTest extends TestCase {
.setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE")))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(0)).setTaxExemptionReason("Kein Ausweis der Umsatzsteuer bei innergemeinschaftlichen Lieferungen").setTaxCategoryCode("K"), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(0)).setTaxExemptionReason("Kein Ausweis der Umsatzsteuer bei innergemeinschaftlichen Lieferungen").setTaxCategoryCode("K"), price, new BigDecimal(1.0)))
);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
@@ -413,8 +477,8 @@ public class ZF2PushTest extends TestCase {
String orgname = "Test company";
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
@@ -423,17 +487,17 @@ public class ZF2PushTest extends TestCase {
ze.setProducer("My Application").setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("extended");
// ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname,"teststr", "55232","teststadt","DE")).setOwnTaxID("4711").setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")).setNumber(number)
// .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
// .addItem(new Item(new Product("Testprodukt", "", "H84", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addVATID("DE0815").addTaxID("4711"))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0816")
.setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562")))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).setReverseCharge(), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setReverseCharge(), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setReverseCharge(), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setReverseCharge(), price, new BigDecimal(2.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).setReverseCharge(), price, new BigDecimal(1.0)))
);
String theXML = new String(ze.getProvider().getXML());
@@ -464,8 +528,8 @@ public class ZF2PushTest extends TestCase {
String orgname = "Test company";
String number = "123";
String amountStr = "3.00";
BigDecimal amount = new BigDecimal(amountStr);
String priceStr = "3.00";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
@@ -477,9 +541,9 @@ public class ZF2PushTest extends TestCase {
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815"))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addCharge(new Charge(new BigDecimal(0.5)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK"))
.addAllowance(new Allowance(new BigDecimal(0.2)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK"))
);
@@ -540,7 +604,7 @@ public class ZF2PushTest extends TestCase {
.setContractReferencedDocument(contractID)
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addGlobalID(gln).setEmail("recipient@test.org").addVATID("DE4711")
.setContact(new Contact("Franz Müller", "01779999999", "franz@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE").setFax("++49555123456")).setAdditionalAddress("Hinterhaus 3"))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).setId("a123").addBuyerOrderReferencedDocumentID("orderId").addBuyerOrderReferencedDocumentLineID("xxx").addReferencedLineID("xxx").addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15")))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).setId("a123").addBuyerOrderReferencedDocumentID("orderId").addBuyerOrderReferencedDocumentLineID("xxx").addReferencedLineID("xxx").addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15")))
.addCharge(new Charge(new BigDecimal(0.5)).setReason("quick delivery charge").setTaxPercent(new BigDecimal(16)))
.addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16)))
.addCashDiscount(new CashDiscount(new BigDecimal(2), 14))
@@ -631,7 +695,7 @@ public class ZF2PushTest extends TestCase {
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815"))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)).addAllowance(new Allowance(BigDecimal.ONE)), new BigDecimal(500.0), qty).addAllowance(new Allowance(new BigDecimal(300)).setTaxPercent(new BigDecimal(19))))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)).addAllowance(new Allowance(BigDecimal.ONE)), new BigDecimal(500.0), qty).addAllowance(new Allowance(new BigDecimal(300)).setTaxPercent(new BigDecimal(19))))
.addAllowance(new Allowance(new BigDecimal(600)).setTaxPercent(new BigDecimal(19)))
);
String theXML = new String(ze.getProvider().getXML());
@@ -675,10 +739,10 @@ public class ZF2PushTest extends TestCase {
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815"))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)).addCharge(new Charge().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK")))
.addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReason("Mengenrabatt"))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, new BigDecimal(1.0))).addCharge(new Charge().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReasonCode("ABK"))
.addAllowance(new Allowance().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19)).setReason("Mengenrabatt"))
);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
@@ -691,7 +755,7 @@ public class ZF2PushTest extends TestCase {
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_RELATIVECHARGESALLOWANCESPDF);
assertEquals("CHF", zi.getInvoiceCurrencyCode());
assertEquals("11.10", zi.getAmount());
assertEquals("10.71", zi.getAmount());
assertEquals(orgname, zi.getHolder());
assertEquals(number, zi.getForeignReference());
try {
@@ -726,9 +790,9 @@ public class ZF2PushTest extends TestCase {
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815"))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0815"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty)).setCorrection("0815");
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty)).setCorrection("0815");
ze.setTransaction(i);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
@@ -777,9 +841,9 @@ public class ZF2PushTest extends TestCase {
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815").addBankDetails(new BankDetails("DE88200800000970375700", "COBADEFFXXX")))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0815"))
.setNumber(number).setDespatchAdviceReferencedDocumentID(despatchAdviceReferencedDocumentID)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty)).setCreditNote();
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty)).setCreditNote();
ze.setTransaction(i);
String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
@@ -831,7 +895,7 @@ public class ZF2PushTest extends TestCase {
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815").addBankDetails(new BankDetails("DE88200800000970375700", "COBADEFFXXX")))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0815"))
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty));
.addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(19)), price, qty));
// empty strings for document id's
i.setSellerOrderReferencedDocumentID("")

View File

@@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.mustangproject.*;
import org.skyscreamer.jsonassert.JSONAssert;
import javax.xml.xpath.XPathExpressionException;
import java.io.File;
@@ -38,6 +39,7 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@@ -264,7 +266,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
}
assertFalse(hasExceptions);
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("18.92"), tc.getGrandTotal());
assertEquals(new BigDecimal("18.33"), tc.getGrandTotal());
}
public void testIBANImport() {
@@ -405,8 +407,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
ObjectMapper mapper = new ObjectMapper();
String jsonArray = mapper.writeValueAsString(i);
// assertEquals("",jsonArray);
JSONAssert.assertEquals("{\"documentCode\":\"380\",\"number\":\"471102\",\"currency\":\"EUR\",\"paymentTermDescription\":\"Der Betrag in Höhe von EUR 529,87 wird am 20.03.2018 von Ihrem Konto per SEPA-Lastschrift eingezogen.\\n \",\"issueDate\":1520121600000,\"deliveryDate\":1520121600000,\"sender\":{\"name\":\"Lieferant GmbH\",\"zip\":\"80333\",\"street\":\"Lieferantenstraße 20\",\"location\":\"München\",\"country\":\"DE\",\"taxID\":\"201/113/40209\",\"vatID\":\"DE123456789\",\"debitDetails\":[{\"mandate\":\"REF A-123\",\"paymentMeansCode\":\"59\",\"paymentMeansInformation\":\"SEPA direct debit\",\"iban\":\"DE21860000000086001055\"}],\"vatid\":\"DE123456789\"},\"recipient\":{\"name\":\"Kunden AG Mitte\",\"zip\":\"69876\",\"street\":\"Kundenstraße 15\",\"location\":\"Frankfurt\",\"country\":\"DE\",\"bankDetails\":[{\"paymentMeansCode\":\"58\",\"paymentMeansInformation\":\"SEPA credit transfer\",\"iban\":\"DE21860000000086001055\"}]},\"totalPrepaidAmount\":0.00,\"creditorReferenceID\":\"DE98ZZZ09999999999\",\"valid\":false,\"zfitems\":[{\"price\":9.9000,\"quantity\":20.0000,\"basisQuantity\":1.0000,\"id\":\"1\",\"product\":{\"unit\":\"H87\",\"name\":\"Trennblätter A4\",\"taxCategoryCode\":\"S\",\"vatpercent\":19.00,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"value\":9.9000},{\"price\":5.5000,\"quantity\":50.0000,\"basisQuantity\":1.0000,\"id\":\"2\",\"product\":{\"unit\":\"H87\",\"name\":\"Joghurt Banane\",\"taxCategoryCode\":\"S\",\"vatpercent\":7.00,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"value\":5.5000}],\"tradeSettlement\":[{\"mandate\":\"REF A-123\",\"paymentMeansCode\":\"59\",\"paymentMeansInformation\":\"SEPA direct debit\",\"iban\":\"DE21860000000086001055\"}],\"ownTaxID\":\"201/113/40209\",\"ownZIP\":\"80333\",\"ownCountry\":\"DE\",\"ownVATID\":\"DE123456789\",\"ownLocation\":\"München\",\"ownStreet\":\"Lieferantenstraße 20\"}",jsonArray,false);
} catch (IOException e) {
fail("IOException not expected");
@@ -415,8 +416,37 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public static Date atStartOfDay(Date date) {
ZoneId tz=ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0));
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), tz);
LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
return Date.from(startOfDay.atZone(tz).toInstant());
}
public void testImportAllowances() {
try {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushItemChargesAllowances.pdf");
Invoice i = zii.extractInvoice();
ObjectMapper mapper = new ObjectMapper();
String jsonArray = mapper.writeValueAsString(i);
SimpleDateFormat iso=new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat german=new SimpleDateFormat("dd.MM.yyyy");
Date now=new Date();
Date morning=atStartOfDay(now);
String expectedDueDate= String.valueOf(morning.toInstant().getEpochSecond() *1000);
String expectedIssueDate= String.valueOf(morning.toInstant().getEpochSecond() *1000);
String expectedPaymentTermDesciption="Please remit until "+german.format(now);
JSONAssert.assertEquals("{ \"documentCode\": \"380\", \"number\": \"123\", \"currency\": \"EUR\", \"paymentTermDescription\": \""+expectedPaymentTermDesciption+"\", \"issueDate\": "+expectedIssueDate+", \"dueDate\": "+expectedDueDate+", \"sender\": { \"name\": \"Test company\", \"zip\": \"55232\", \"street\": \"teststr\", \"location\": \"teststadt\", \"country\": \"DE\", \"taxID\": \"4711\", \"vatID\": \"DE0815\", \"vatid\": \"DE0815\" }, \"recipient\": { \"name\": \"Franz Müller\", \"zip\": \"55232\", \"street\": \"teststr.12\", \"location\": \"Entenhausen\", \"country\": \"DE\", \"contact\": { \"name\": \"contact testname\", \"phone\": \"123456\", \"email\": \"contact.testemail@example.org\", \"fax\": \"0911623562\" } }, \"totalPrepaidAmount\": 0.00, \"valid\": true, \"zfitems\": [ { \"price\": 3.0000, \"quantity\": 1.0000, \"basisQuantity\": 1.0000, \"id\": \"1\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemAllowances\": [ { \"totalAmount\": 0.10, \"taxPercent\": 0, \"categoryCode\": \"S\" } ], \"value\": 3.0000 }, { \"price\": 3.0000, \"quantity\": 1.0000, \"basisQuantity\": 1.0000, \"id\": \"2\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemAllowances\": [ { \"percent\": 50.00, \"totalAmount\": 1.5, \"basisAmount\": 3.00, \"taxPercent\": 0, \"reason\": \"In love with salesperson\", \"categoryCode\": \"S\" } ], \"value\": 3.0000 }, { \"price\": 3.0000, \"quantity\": 2.0000, \"basisQuantity\": 1.0000, \"id\": \"3\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemCharges\": [ { \"totalAmount\": 1.00, \"taxPercent\": 0, \"reason\": \"AnotherReason\", \"categoryCode\": \"S\" } ], \"value\": 3.0000 }, { \"price\": 3.0000, \"quantity\": 1.0000, \"basisQuantity\": 1.0000, \"id\": \"4\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemCharges\": [ { \"totalAmount\": 1.00, \"taxPercent\": 0, \"reason\": \"Yet another reason\", \"categoryCode\": \"S\" } ], \"itemAllowances\": [ { \"totalAmount\": 1.00, \"taxPercent\": 0, \"reason\": \"Something completely strange\", \"categoryCode\": \"S\" } ], \"value\": 3.0000 } ], \"ownCountry\": \"DE\", \"zfcharges\": [ { \"totalAmount\": 1.00, \"taxPercent\": 19.00, \"reason\": \"AReason\", \"reasonCode\": \"ABK\", \"categoryCode\": \"S\" } ], \"ownVATID\": \"DE0815\", \"ownStreet\": \"teststr\", \"ownTaxID\": \"4711\", \"ownLocation\": \"teststadt\", \"ownZIP\": \"55232\"}",jsonArray,true);
} catch (IOException e) {
fail("IOException not expected");
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public void testImportMinimum() {

View File

@@ -131,6 +131,10 @@ costs, losses or damages could normally have been foreseen.-->
<ram:SellerAssignedID>CO-123/V2A</ram:SellerAssignedID>
<ram:BuyerAssignedID>Toolbox 0815</ram:BuyerAssignedID>
<ram:Name>Stahlcoil</ram:Name>
<ram:ApplicableProductCharacteristic>
<ram:Description>LeoID</ram:Description>
<ram:Value>704310.0105636504</ram:Value>
</ram:ApplicableProductCharacteristic>
<ram:OriginTradeCountry>
<ram:ID>DE</ram:ID>
</ram:OriginTradeCountry>

13
pom.xml
View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.17.1-SNAPSHOT</version> <packaging>pom</packaging>
<version>2.18.1-SNAPSHOT</version> <packaging>pom</packaging>
<name>Mustang</name>
<modules>
@@ -70,28 +70,27 @@
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.13</version>
<version>1.7.0</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<nexusUrl>https://ossrh-staging-api.central.sonatype.com/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<runOrder>alphabetical</runOrder>
<argLine>-Duser.timezone=UTC</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-javadoc</id>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.17.1-SNAPSHOT</version>
<version>2.18.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
@@ -11,7 +11,7 @@
<name>Library to validate e-invoices (ZUGFeRD, Factur-X and Xrechnung)</name>
<packaging>jar</packaging>
<version>2.17.1-SNAPSHOT</version>
<version>2.18.1-SNAPSHOT</version>
<repositories>
<repository>
<!-- for jargs -->
@@ -38,7 +38,7 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>library</artifactId>
<version>2.17.1-SNAPSHOT</version>
<version>2.18.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
@@ -129,8 +129,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<runOrder>alphabetical</runOrder>
<argLine>-Duser.timezone=UTC</argLine>
</configuration>
</plugin>
<!-- allow getImplementationVersion for the pom.xml -->

View File

@@ -12,7 +12,6 @@ import java.util.Calendar;
import java.util.EnumSet;
import java.util.HashMap;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -130,136 +129,137 @@ public class PDFValidator extends Validator {
final Document docXMP;
if (xmp == null || xmp.length() == 0) {
if (xmp == null || xmp.isEmpty()) {
context.addResultItem(new ValidationResultItem(ESeverity.error, "Invalid XMP Metadata not found")
.setSection(17).setPart(EPart.pdf));
}
else
/*
* checking for sth like <zf:ConformanceLevel>EXTENDED</zf:ConformanceLevel>
* <zf:DocumentType>INVOICE</zf:DocumentType>
* <zf:DocumentFileName>ZUGFeRD-invoice.xml</zf:DocumentFileName>
* <zf:Version>1.0</zf:Version>
*/
try {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
factory.setXIncludeAware(false);
else {
/*
* checking for sth like <zf:ConformanceLevel>EXTENDED</zf:ConformanceLevel>
* <zf:DocumentType>INVOICE</zf:DocumentType>
* <zf:DocumentFileName>ZUGFeRD-invoice.xml</zf:DocumentFileName>
* <zf:Version>1.0</zf:Version>
*/
try {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
factory.setXIncludeAware(false);
final DocumentBuilder builder = factory.newDocumentBuilder();
final InputSource is = new InputSource(new StringReader(xmp));
docXMP = builder.parse(is);
final DocumentBuilder builder = factory.newDocumentBuilder();
final InputSource is = new InputSource(new StringReader(xmp));
docXMP = builder.parse(is);
final XPathFactory xpathFactory = XPathFactory.newInstance();
final XPathFactory xpathFactory = XPathFactory.newInstance();
// Create XPath object XPath xpath = xpathFactory.newXPath(); XPathExpression
// Create XPath object XPath xpath = xpathFactory.newXPath(); XPathExpression
final XPath xpath = xpathFactory.newXPath();
// xpath.compile("//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/[local-name()=\"ID\"]");
// evaluate expression result on XML document ndList = (NodeList)
final XPath xpath = xpathFactory.newXPath();
// xpath.compile("//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/[local-name()=\"ID\"]");
// evaluate expression result on XML document ndList = (NodeList)
// get the first element
XPathExpression xpr = xpath.compile(
"//*[local-name()=\"ConformanceLevel\"]|//*[local-name()=\"Description\"]/@ConformanceLevel");
NodeList nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET);
// get the first element
XPathExpression xpr = xpath.compile(
"//*[local-name()=\"ConformanceLevel\"]|//*[local-name()=\"Description\"]/@ConformanceLevel");
NodeList nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET);
if (nodes.getLength() == 0) {
context.addResultItem(
new ValidationResultItem(ESeverity.error, "XMP Metadata: ConformanceLevel not found")
.setSection(11).setPart(EPart.pdf));
}
boolean conformanceLevelValid = false;
for (int i = 0; i < nodes.getLength(); i++) {
final String[] valueArray = {"BASIC WL", "BASIC", "MINIMUM", "EN 16931", "COMFORT", "CIUS", "EXTENDED", "XRECHNUNG"};
if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) {
conformanceLevelValid = true;
}
}
if (!conformanceLevelValid) {
context.addResultItem(new ValidationResultItem(
ESeverity.error,
"XMP Metadata: ConformanceLevel contains invalid value"
).setSection(12).setPart(EPart.pdf));
}
xpr = xpath.compile("//*[local-name()=\"DocumentType\"]|//*[local-name()=\"Description\"]/@DocumentType");
nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET);
if (nodes.getLength() == 0) {
context.addResultItem(new ValidationResultItem(ESeverity.error, "XMP Metadata: DocumentType not found")
.setSection(13).setPart(EPart.pdf));
}
boolean documentTypeValid = false;
for (int i = 0; i < nodes.getLength(); i++) {
if (nodes.item(i).getTextContent().equals("INVOICE") || nodes.item(i).getTextContent().equals("ORDER")
|| nodes.item(i).getTextContent().equals("ORDER_RESPONSE") || nodes.item(i).getTextContent()
.equals("ORDER_CHANGE")) {
documentTypeValid = true;
}
}
if (!documentTypeValid) {
context.addResultItem(
new ValidationResultItem(ESeverity.error, "XMP Metadata: DocumentType invalid")
.setSection(14).setPart(EPart.pdf));
}
xpr = xpath.compile(
"//*[local-name()=\"DocumentFileName\"]|//*[local-name()=\"Description\"]/@DocumentFileName");
nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET);
if (nodes.getLength() == 0) {
context.addResultItem(
new ValidationResultItem(ESeverity.error, "XMP Metadata: DocumentFileName not found")
.setSection(21).setPart(EPart.pdf));
}
boolean documentFilenameValid = false;
for (int i = 0; i < nodes.getLength(); i++) {
final String[] valueArray = {"factur-x.xml", "ZUGFeRD-invoice.xml", "zugferd-invoice.xml", "xrechnung.xml", "order-x.xml"};
if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) {
documentFilenameValid = true;
if (nodes.getLength() == 0) {
context.addResultItem(
new ValidationResultItem(ESeverity.error, "XMP Metadata: ConformanceLevel not found")
.setSection(11).setPart(EPart.pdf));
}
// e.g. ZUGFeRD-invoice.xml
}
if (!documentFilenameValid) {
boolean conformanceLevelValid = false;
for (int i = 0; i < nodes.getLength(); i++) {
context.addResultItem(new ValidationResultItem(
ESeverity.error,
"XMP Metadata: DocumentFileName contains invalid value"
).setSection(19).setPart(EPart.pdf));
}
xpr = xpath.compile("//*[local-name()=\"Version\"]|//*[local-name()=\"Description\"]/@Version");
nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET);
final String[] valueArray = {"BASIC WL", "BASIC", "MINIMUM", "EN 16931", "COMFORT", "CIUS", "EXTENDED", "XRECHNUNG"};
if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) {
conformanceLevelValid = true;
}
}
if (!conformanceLevelValid) {
context.addResultItem(new ValidationResultItem(
ESeverity.error,
"XMP Metadata: ConformanceLevel contains invalid value"
).setSection(12).setPart(EPart.pdf));
// get all child nodes
// NodeList nodes = element.getChildNodes();
// expr.evaluate(docXMP, XPathConstants.NODESET);
// print the text content of each child
if (nodes.getLength() == 0) {
context.addResultItem(new ValidationResultItem(ESeverity.error, "XMP Metadata: Version not found")
.setSection(15).setPart(EPart.pdf));
}
}
xpr = xpath.compile("//*[local-name()=\"DocumentType\"]|//*[local-name()=\"Description\"]/@DocumentType");
nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET);
boolean versionValid = false;
for (int i = 0; i < nodes.getLength(); i++) {
final String[] valueArray = {"1.0", "1p0", "2p0", "1.2", "2.0", "2.1", "2.2", "2.3", "3.0"}; //1.2, 2.0, 2.1, 2.2, 2.3 and 3.0 are for xrechnung 1.2, 2p0 can be ZF 2.0, 2.1, 2.1.1
if (nodes.getLength() == 0) {
context.addResultItem(new ValidationResultItem(ESeverity.error, "XMP Metadata: DocumentType not found")
.setSection(13).setPart(EPart.pdf));
}
if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) {
versionValid = true;
} // e.g. 1.0
}
if (!versionValid) {
context.addResultItem(
new ValidationResultItem(ESeverity.error, "XMP Metadata: Version contains invalid value")
.setSection(16).setPart(EPart.pdf));
boolean documentTypeValid = false;
for (int i = 0; i < nodes.getLength(); i++) {
if (nodes.item(i).getTextContent().equals("INVOICE") || nodes.item(i).getTextContent().equals("ORDER")
|| nodes.item(i).getTextContent().equals("ORDER_RESPONSE") || nodes.item(i).getTextContent()
.equals("ORDER_CHANGE")) {
documentTypeValid = true;
}
}
if (!documentTypeValid) {
context.addResultItem(
new ValidationResultItem(ESeverity.error, "XMP Metadata: DocumentType invalid")
.setSection(14).setPart(EPart.pdf));
}
xpr = xpath.compile(
"//*[local-name()=\"DocumentFileName\"]|//*[local-name()=\"Description\"]/@DocumentFileName");
nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET);
if (nodes.getLength() == 0) {
context.addResultItem(
new ValidationResultItem(ESeverity.error, "XMP Metadata: DocumentFileName not found")
.setSection(21).setPart(EPart.pdf));
}
boolean documentFilenameValid = false;
for (int i = 0; i < nodes.getLength(); i++) {
final String[] valueArray = {"factur-x.xml", "ZUGFeRD-invoice.xml", "zugferd-invoice.xml", "xrechnung.xml", "order-x.xml"};
if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) {
documentFilenameValid = true;
}
// e.g. ZUGFeRD-invoice.xml
}
if (!documentFilenameValid) {
context.addResultItem(new ValidationResultItem(
ESeverity.error,
"XMP Metadata: DocumentFileName contains invalid value"
).setSection(19).setPart(EPart.pdf));
}
xpr = xpath.compile("//*[local-name()=\"Version\"]|//*[local-name()=\"Description\"]/@Version");
nodes = (NodeList) xpr.evaluate(docXMP, XPathConstants.NODESET);
// get all child nodes
// NodeList nodes = element.getChildNodes();
// expr.evaluate(docXMP, XPathConstants.NODESET);
// print the text content of each child
if (nodes.getLength() == 0) {
context.addResultItem(new ValidationResultItem(ESeverity.error, "XMP Metadata: Version not found")
.setSection(15).setPart(EPart.pdf));
}
boolean versionValid = false;
for (int i = 0; i < nodes.getLength(); i++) {
final String[] valueArray = {"1.0", "1p0", "2p0", "1.2", "2.0", "2.1", "2.2", "2.3", "3.0"}; //1.2, 2.0, 2.1, 2.2, 2.3 and 3.0 are for xrechnung 1.2, 2p0 can be ZF 2.0, 2.1, 2.1.1
if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) {
versionValid = true;
} // e.g. 1.0
}
if (!versionValid) {
context.addResultItem(
new ValidationResultItem(ESeverity.error, "XMP Metadata: Version contains invalid value")
.setSection(16).setPart(EPart.pdf));
}
} catch (final SAXException | IOException | ParserConfigurationException | XPathExpressionException e) {
LOGGER.error(e.getMessage(), e);
}
} catch (final SAXException | IOException | ParserConfigurationException | XPathExpressionException e) {
LOGGER.error(e.getMessage(), e);
}
zfXML = zi.getUTF8();
@@ -306,7 +306,7 @@ public class PDFValidator extends Validator {
final HashMap<String, byte[]> additionalData = zi.getAdditionalData();
for (final String filename : additionalData.keySet()) {
// validating xml in byte[] additionalData.get(filename)
LOGGER.info("validating additionalData " + filename);
LOGGER.info("validating additionalData {}", filename);
validateSchema(additionalData.get(filename), "ad/basic/additional_data_base_schema.xsd", 2, EPart.pdf);
}

View File

@@ -32,13 +32,13 @@ public class ValidationContext {
}
if (logger != null) {
if ((vr.getSeverity() == ESeverity.fatal) || (vr.getSeverity() == ESeverity.exception)) {
logger.error("Fatal Error " + vr.getSection() + ": " + vr.getMessage());
logger.error("Fatal Error {}: {}", vr.getSection(), vr.getMessage());
} else if ((vr.getSeverity() == ESeverity.error)) {
logger.error("Error " + vr.getSection() + ": " + vr.getMessage());
logger.error("Error {}: {}", vr.getSection(), vr.getMessage());
} else if (vr.getSeverity() == ESeverity.warning) {
logger.warn("Warning " + vr.getSection() + ": " + vr.getMessage());
logger.warn("Warning {}: {}", vr.getSection(), vr.getMessage());
} else if (vr.getSeverity() == ESeverity.notice) {
logger.info("Notice " + vr.getSection() + ": " + vr.getMessage());
logger.info("Notice {}: {}", vr.getSection(), vr.getMessage());
}
}
@@ -106,20 +106,17 @@ public class ValidationContext {
}
public String getXMLResult() {
String res = getCustomXML();
if (results.size() > 0) {
res += "<messages>";
StringBuilder res = new StringBuilder(getCustomXML());
if (results != null && !results.isEmpty()) {
res.append("<messages>");
for (final ValidationResultItem validationResultItem : results) {
// xml and pdf are handled in their respective sections
res.append(validationResultItem.getXMLOnce()).append("\n");
}
res.append("</messages>");
}
for (final ValidationResultItem validationResultItem : results) {
// xml and pdf are handled in their respective sections
res += validationResultItem.getXMLOnce() + "\n";
}
if (results.size() > 0) {
res += "</messages>";
}
res += "<summary status=\"" + (isValid ? "valid" : "invalid") + "\"/>";
return res;
res.append("<summary status=\"").append(isValid ? "valid" : "invalid").append("\"/>");
return res.toString();
}
/***

View File

@@ -8,6 +8,7 @@ import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.Calendar;
import javax.xml.XMLConstants;
@@ -20,7 +21,9 @@ import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.mustangproject.CalculatedInvoice;
import org.mustangproject.XMLTools;
import org.mustangproject.ZUGFeRD.ZUGFeRDInvoiceImporter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
@@ -222,13 +225,7 @@ public class XMLValidator extends Validator {
isExtended = context.getProfile().contains("extended");
validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "OX_10/comfort/SCRDMCCBDACIOMessageStructure_100pD20B.xsd", 99, EPart.ox);
xsltFilename = "/xslt/OX_10/comfort/SCRDMCCBDACIOMessageStructure_100pD20B_COMFORT.xslt";
} else if (root.getLocalName().equalsIgnoreCase("SCRDMCCBDACIOMessageStructure")) {
context.setGeneration("1");
isOrderX = true;
validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "OX_10/comfort/SCRDMCCBDACIOMessageStructure_100pD20B.xsd", 99, EPart.ox);
xsltFilename = "/xslt/OX_10/comfort/SCRDMCCBDACIOMessageStructure_100pD20B_COMFORT.xslt";
} else if (root.getLocalName().equalsIgnoreCase("CrossIndustryInvoice")) { // ZUGFeRD 2.0 or Factur-X
context.setGeneration("2");
@@ -306,7 +303,7 @@ public class XMLValidator extends Validator {
if (!xrVersion.equals("12") && !xrVersion.equals("20") && !xrVersion.equals("21") && !xrVersion.equals("22") && !xrVersion.equals("23") && !xrVersion.equals("30")) {
throw new Exception("Unsupported XR version");
}
LOGGER.debug("is XRechnung v" + xrVersion);
LOGGER.debug("is XRechnung v{}", xrVersion);
xsltFilename = "/xslt/XR_" + xrVersion + "/XRechnung-UBL-validation.xslt";
XrechnungSeverity = ESeverity.error;
mainSchematronSectionErrorTypeCode = 27;
@@ -387,6 +384,7 @@ public class XMLValidator extends Validator {
}
}
}
checkArithmetics(context);
} catch (final IrrecoverableValidationError er) {
@@ -410,6 +408,28 @@ public class XMLValidator extends Validator {
}
private void checkArithmetics(ValidationContext context) {
ZUGFeRDInvoiceImporter zi=new ZUGFeRDInvoiceImporter();
try {
zi.fromXML(zfXML);
CalculatedInvoice ci=new CalculatedInvoice();
zi.extractInto(ci);
} catch ( ArithmeticException e) {
try {
context.addResultItem(new ValidationResultItem(ESeverity.warning, "Arithmetical issue:"+e.getMessage()).setSection(10));
} catch (IrrecoverableValidationError ie) {
LOGGER.error(ie.getMessage(), ie);
}
} catch (XPathExpressionException e) {
LOGGER.error(e.getMessage(), e);
} catch (ParseException e) {
LOGGER.error(e.getMessage(), e);
}
}
public void validateXR(String xml, ESeverity errorImpact) throws IrrecoverableValidationError {
//Guideline ID=urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_1.2 or
@@ -507,7 +527,7 @@ public class XMLValidator extends Validator {
}
}
LOGGER.info("FailedAssert ", thisFailText);
LOGGER.info("FailedAssert {}", thisFailText);
context.addResultItem(new ValidationResultItem(severity, thisFailText + thisFailIDStr + " from " + xsltFilename + ")")
.setLocation(thisFailLocation).setCriterion(thisFailTest).setSection(section).setID(thisFailID)

View File

@@ -17,8 +17,7 @@ public class ResourceCase extends TestCase {
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceCase.class.getCanonicalName()); // log output is
public static File getResourceAsFile(String resourcePath) {
try {
InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
try(InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath)) {
if (in == null) {
return null;
}
@@ -42,8 +41,7 @@ public class ResourceCase extends TestCase {
}
public static byte[] getResourceAsByteArray(String resourcePath) {
try {
InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
try(InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath)) {
if (in == null) {
return null;
}

View File

@@ -8,6 +8,8 @@ import org.xmlunit.builder.Input;
import org.xmlunit.xpath.JAXPXPathEngine;
import org.xmlunit.xpath.XPathEngine;
import static org.xmlunit.assertj.XmlAssert.assertThat;
public class XMLValidatorTest extends ResourceCase {
public void testZF2XMLValidation() {
@@ -282,6 +284,30 @@ public class XMLValidatorTest extends ResourceCase {
}
public void testArithmetics() {
final ValidationContext ctx = new ValidationContext(null);
final XMLValidator xv = new XMLValidator(ctx);
final XPathEngine xpath = new JAXPXPathEngine();
File tempFile = getResourceAsFile("invalidArithmetics.xml");
try {
xv.setFilename(tempFile.getAbsolutePath());
xv.validate();
String s="<validation>" + xv.getXMLResult() + "</validation>";
Source source = Input.fromString(s).build();
String content = xpath.evaluate("/validation/summary/@status", source);
assertEquals("valid", content);
assertThat(s).valueByXPath("count(//warning)")
.asInt()
.isEqualTo(1);
} catch (final IrrecoverableValidationError e) {
// ignore, will be in XML output anyway
}
}
public void testXRValidationUBL() {
ValidationContext ctx = new ValidationContext(null);
XMLValidator xv = new XMLValidator(ctx);

View File

@@ -219,7 +219,7 @@ public class ZUGFeRDValidatorTest extends ResourceCase {
.isEqualTo(2);
assertThat(res).valueByXPath("count(//warning)")
.asInt()
.isEqualTo(2);
.isEqualTo(3);
assertThat(res).valueByXPath("count(//notice)")
.asInt()

View File

@@ -0,0 +1,186 @@
<?xml version='1.0' encoding="UTF-8" standalone="yes"?>
<rsm:CrossIndustryInvoice xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>RE-20171118/506</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime><udt:DateTimeString format="102">20171118</udt:DateTimeString></ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Künstlerische Gestaltung (Stunde): Einer Beispielrechnung</ram:Name>
<ram:Description></ram:Description>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>160.0000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>160.0000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="HUR">2.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>160.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>2</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Luftballon: Bunt, ca. 500ml</ram:Name>
<ram:Description></ram:Description>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>0.7900</ram:ChargeAmount>
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>0.7900</ram:ChargeAmount>
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">400.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>316.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>3</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Heiße Luft pro Liter</ram:Name>
<ram:Description></ram:Description>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>0.1000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>0.1000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="LTR">200.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>20.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>Bei Spiel GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>12345</ram:PostcodeCode>
<ram:LineOne>Ecke 12</ram:LineOne>
<ram:CityName>Stadthausen</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="FC">22/815/0815/4</ram:ID>
</ram:SpecifiedTaxRegistration>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE136695976</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Theodor Est</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>88802</ram:PostcodeCode>
<ram:LineOne>Bahnstr. 42</ram:LineOne>
<ram:CityName>Spielkreis</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE999999999</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime><udt:DateTimeString format="102">20171117</udt:DateTimeString></ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:PaymentReference>RE-20171118/506</ram:PaymentReference>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementPaymentMeans>
<ram:TypeCode>42</ram:TypeCode>
<ram:Information>Überweisung</ram:Information>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>DE88 2008 0000 0970 3757 00</ram:IBANID>
</ram:PayeePartyCreditorFinancialAccount>
<ram:PayeeSpecifiedCreditorFinancialInstitution>
<ram:BICID>COBADEFFXXX</ram:BICID>
</ram:PayeeSpecifiedCreditorFinancialInstitution>
</ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>11.20</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>160.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>63.84</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>336.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Zahlbar ohne Abzug bis 09.12.2017</ram:Description>
<ram:DueDateDateTime><udt:DateTimeString format="102">20171209</udt:DateTimeString></ram:DueDateDateTime>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>496.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>496.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">75.04</ram:TaxTotalAmount>
<ram:GrandTotalAmount>571.04</ram:GrandTotalAmount>
<ram:DuePayableAmount>571.04</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>