Merge branch 'master' into patch-1

This commit is contained in:
Jochen Staerk
2025-01-07 11:25:41 +01:00
committed by GitHub
141 changed files with 29013 additions and 26972 deletions

View File

@@ -1,3 +1,77 @@
- 639
- 633
-626,
-622,
-356
allow to add includedNotes with type
- - 645
- 631 multiple invoice referenced documents
- 629
- 630 #296 #565
-
2.15.2
=======
2024-12-19
- correcly write charge reason codes also for non-Xrechnung #617
- correctly import additional referenced documents into invoice/corrected setting of attachments from jackson
- corrected parseException structure
- allow 1p0 as potential xmp version number
- #618 import BT-20
- #599 add tax category code for free export
- #600 Fixes a problem where a stream was not safely closed
2.15.1
=======
2024-12-07
- #566 Failed to parse PDF - Could not reproduce the invoice
- closes #579 prepaidamount is only read in UBL
- #581 parse lineTotalAmount, TaxBasisAmount, duePayableAmount
- #576 read lineid, #578 set lineid
- log error ids, be able to access them from context
- #503 import more ubl
- allow jackson to run over more classes, e.g., DirectDebit, bean contructor for direct debit
- allow json in document includedNotes and
- #591 Import IncludedNotes also on item level
- #595 Treat all fatal XR schematron rules as errors, not as warnings.
- #577 dom4j: exclude all (optional) dependencies to avoid potential conflicts.
- #575 Fix compilation problems.
- #573 Feature/category code
- #601 exceptions in metrics
- #606 also parse BT-25
2.15.0
=======
2024-11-18
- #435 use invoiceimporter as common technical basis also for zugferdimporter
- also import delivery address
- #527 metrics may raise error on some pdf files
- #517 read product GlobalID
- #380 Added test for input stream validation
- #518 corrently validate more XRechnung versions
- make document charges and allowances serializable
- #523 Verapdf claims PDF-A/3s created witth visualize are invalid
- #530 duedate can not be set directly
- #532 support validation warnings!
- #534 new signature
- #538 Mustang validator always claims PDF is invalid if flavour is PDF/A-3A
- #555 be able to validate ubl credit notes
- when parsing now distinguishing between the parseExceptions StructureException and ArithmetricException
- #554 Import IncludedNotes on invoice extraction
- #542 Visualize SpecifiedLogisticsServiceCharge
- #531 Support ZUGFeRD 2.3.2
- #480 Support netherlands Euro
2.14.2
=======
2024-10-14
- also parse BICs in InvoiceImporter not only IBANs
- #509 CLI currently does not write a logfile
- #505 crash after invoking ZUGFeRD2PullProvider
- #506 Fix POM missing dependencies
2.14.1
=======
2024-10-06

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.15.0-SNAPSHOT</version>
<version>2.15.3-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.15.0-SNAPSHOT</version>
<version>2.15.3-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.15.0-SNAPSHOT</version>
<version>2.15.3-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
-->
@@ -35,11 +35,30 @@
<version>1.8.0</version>
</dependency>
<!-- logging -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.13</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.5.13</version>
</dependency>
<dependency>
<!-- This library is needed so that logback stderr output is sent to, well, stderr, otherwise it lands in stdout -->
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>3.1.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.12</version>
</dependency>
<!-- end of logging -->
<dependency>
<groupId>org.junit.jupiter</groupId>

View File

@@ -51,7 +51,9 @@ public class FileChecker {
if ((!isPDF) && (!thisRun.shallIgnoreFileExt())) {
return false;
}
ZUGFeRDImporter zi = new ZUGFeRDImporter(filename);
ZUGFeRDImporter zi = new ZUGFeRDImporter();
zi.doIgnoreCalculationErrors();
zi.setPDFFilename(filename);
try {
if (zi.canParse()) {
thisRun.incZUGFeRDCount(zi.getVersion());

View File

@@ -19,6 +19,7 @@
package org.mustangproject.commandline;
import org.apache.commons.cli.*;
import org.apache.commons.io.FilenameUtils;
import org.mustangproject.CII.CIIToUBL;
import org.mustangproject.EStandard;
import org.mustangproject.FileAttachment;
@@ -84,6 +85,7 @@ public class Main {
+ " [--logAppend <text>]: text to be added to log line\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
+ " [--source <filename>]: input PDF or XML file\n"
+ " [--log-as-pdf]: save log output as pdf\n"
+ " --action validateExpectInvalid validate directory expecting negative results \n"
+ " [--no-notices]: refrain from reporting notices\n"
+ " Additional parameters (optional - user will be prompted if not defined)\n"
@@ -357,6 +359,7 @@ public class Main {
options.addOption(new Option("d", "directory", true, "which directory to operate on"));
options.addOption(new Option("i", "ignorefileextension", false, "ignore non-matching file extensions"));
options.addOption(new Option("l", "listfromstdin", false, "take list of files from commandline"));
options.addOption(new Option("log-as-pdf", "log-as-pdf", false, "saving log output to pdf file"));
boolean optionsRecognized = false;
String action = "";
@@ -380,6 +383,7 @@ public class Main {
String format = cmd.getOptionValue("format");
String lang = cmd.getOptionValue("language");
Boolean noNotices = cmd.hasOption("no-notices");
Boolean LogAsPDF = cmd.hasOption("log-as-pdf");
String zugferdVersion = cmd.getOptionValue("version");
String zugferdProfile = cmd.getOptionValue("profile");
@@ -427,7 +431,7 @@ public class Main {
performUBL(sourceName, outName);
optionsRecognized = true;
} else if ((action != null) && (action.equals("validate"))) {
optionsRecognized = performValidate(sourceName, noNotices, cmd.getOptionValue("logAppend"));
optionsRecognized = performValidate(sourceName, noNotices, cmd.getOptionValue("logAppend"), LogAsPDF);
} else if ((action != null) && (action.equals("validateExpectValid"))) {
optionsRecognized = performValidateExpect(true, directoryName);
} else if ((action != null) && (action.equals("validateExpectInvalid"))) {
@@ -454,7 +458,7 @@ public class Main {
}
private static boolean performValidate(String sourceName, boolean noNotices, String logAppend) {
private static boolean performValidate(String sourceName, boolean noNotices, String logAppend, boolean createLogAsPDF) {
boolean optionsRecognized;
if (sourceName == null) {
sourceName = getFilenameFromUser("Source PDF or XML", "invoice.pdf", "pdf|xml", true, false);
@@ -466,7 +470,16 @@ public class Main {
if (noNotices) {
zfv.disableNotices();
}
System.out.println(zfv.validate(sourceName));
String validationResultXML = zfv.validate(sourceName);
System.out.println(validationResultXML);
if( createLogAsPDF) {
ValidationLogVisualizer vlvi = new ValidationLogVisualizer();
String fileBasename = FilenameUtils.getBaseName(sourceName);
vlvi.toPDF(validationResultXML, fileBasename + "_result.pdf");
}
optionsRecognized = !zfv.hasOptionsError();
if (!zfv.wasCompletelyValid()) {
System.exit(-1);

View File

@@ -1,8 +1,6 @@
package org.mustangproject.commandline;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -10,18 +8,43 @@ import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
public class CliIT {
public static File getResourceAsFile(String resourcePath) {
try {
InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
if (in == null) {
return null;
}
File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
tempFile.deleteOnExit();
try (FileOutputStream out = new FileOutputStream(tempFile)) {
// copy stream
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
return tempFile;
} catch (IOException e) {
return null;
}
}
@Test
public void testCii2Ubl() throws Exception {
Path output = Paths.get("target/ubl.xml");
Files.deleteIfExists(output);
Path jar = Files.newDirectoryStream(Paths.get("target"), "Mustang-CLI-*.jar").iterator().next();
ProcessBuilder pb = new ProcessBuilder("java", "-jar", jar.toString(),
"--action", "ubl", "--source", "src/test/resources/cii.xml", "--out",
output.toString());
"--action", "ubl", "--source", "src/test/resources/cii.xml", "--out",
output.toString());
pb.redirectErrorStream(true);
Process process = pb.start();
String result = getOutput(process);
@@ -43,4 +66,17 @@ public class CliIT {
return builder.toString();
}
@Test
public void testMetric() {
StatRun sr = new StatRun();
File tempFile = getResourceAsFile("corrupt-factur-x-waytoosmall.pdf");
FileChecker fc = new FileChecker(tempFile.getAbsolutePath(), sr);
fc.checkForZUGFeRD();
System.out.print(fc.getOutputLine());
}
}

View File

@@ -0,0 +1,2 @@
%PDF-1.4
%ェォャュ

View File

@@ -32,9 +32,10 @@ If you set up a Maven project, you can reference the mustang artifact like this:
```xml
<dependency>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.14.0</version>
<groupId>org.mustangproject</groupId>
<artifactId>validator</artifactId>
<version>2.15.0</version>
<classifier>shaded</classifier>
</dependency>
```

View File

@@ -3,13 +3,13 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.15.0-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.15.0-SNAPSHOT</version>
<version>2.15.3-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
@@ -64,7 +64,8 @@
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
<version>12.4</version>
</dependency><!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
@@ -74,7 +75,7 @@
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>fop</artifactId>
<version>2.9</version>
<version>2.10</version>
<exclusions>
<exclusion>
<groupId>xml-apis</groupId>
@@ -82,18 +83,24 @@
</exclusion>
</exclusions>
</dependency>
<!-- JAXB -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>org.eclipse.angus</groupId>
<artifactId>angus-activation</artifactId>
<version>2.0.2</version>
</dependency>
<!-- Apache PDFBox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>preflight</artifactId>
@@ -104,11 +111,26 @@
<artifactId>pdfbox</artifactId>
<version>3.0.2</version>
</dependency>
<!-- DOM4j -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- CII to UBL conversion -->
<dependency>
<groupId>com.helger</groupId>
<artifactId>en16931-cii2ubl</artifactId>
<version>2.2.4</version>
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
@@ -121,27 +143,12 @@
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<!-- CII to UBL conversion -->
<dependency>
<groupId>com.helger</groupId>
<artifactId>en16931-cii2ubl</artifactId>
<version>2.2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<version>2.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-assertj</artifactId>
@@ -193,21 +200,51 @@
</manifest>
<manifestSections>
<manifestSection>
<name>FreeSans.ttf</name>
<name>SourceSansPro-Regular.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>FreeSerif.ttf</name>
<name>SourceSansPro-It.ttf</name>
<manifestEntries>
<Content-Type>application/x-font</Content-Type>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>Times-Bold.ttf</name>
<name>SourceSansPro-Bold.ttf</name>
<manifestEntries>
<Content-Type>application/x-font</Content-Type>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>SourceSansPro-BoldIt.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>SourceSerifPro-Regular.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>SourceSerifPro-It.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>SourceSerifPro-Bold.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>SourceSerifPro-BoldIt.ttf</name>
<manifestEntries>
<Content-Type>font/ttf</Content-Type>
</manifestEntries>
</manifestSection>
</manifestSections>
@@ -232,11 +269,9 @@
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<minimizeJar>false
</minimizeJar><!-- no longer java 11 compatible if set to true because it removes e.g. javax/xml/bind/annotation/XmlSchema-->
<shadedArtifactAttached>true</shadedArtifactAttached>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
@@ -245,18 +280,6 @@
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
<filter>
<artifact>log4j:log4j</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>commons-logging:commons-logging</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters>
</configuration>
<executions>
@@ -265,15 +288,6 @@
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<!--exclude>classworlds:classworlds</exclude> <exclude>junit:junit</exclude>
<exclude>jmock:*</exclude> <exclude>*:xml-apis</exclude> <exclude>org.apache.maven:lib:tests</exclude>
<exclude>log4j:log4j:jar:</exclude -->
</excludes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>

View File

@@ -1,10 +1,16 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.math.BigDecimal;
/***
* (absolute) allowances on item and document level
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Allowance extends Charge {
/***
@@ -28,6 +34,7 @@ public class Allowance extends Charge {
* @return false since its not supposed to be calculated negatively
*/
@Override
@JsonIgnore
public boolean isCharge() {
return false;
}

View File

@@ -2,11 +2,14 @@ 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.IZUGFeRDTradeSettlementPayment;
/**
* provides e.g. the IBAN to transfer money to :-)
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class BankDetails implements IZUGFeRDTradeSettlementPayment {
/**
* the bank account number
@@ -15,15 +18,17 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
/**
* BIC, I believe it's optional
*/
protected String BIC=null;
protected String BIC = null;
/**
* the "name" of the bank account (holder)
*/
protected String accountName=null;
protected String accountName = null;
/***
* bean constructor
*/
public BankDetails() { }
public BankDetails() {
}
/***
* constructor for IBAN only :-)
@@ -32,6 +37,7 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
public BankDetails(String IBAN) {
this.IBAN = IBAN;
}
/***
* constructor for normal use :-)
* @param IBAN the IBAN as string
@@ -55,6 +61,7 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
* identify the IBAN. Of course you will specify your own IBAN in full length but
* if you deduct from a customer's account you may e.g. leave out the first or last
* digits so that nobody spying on the invoice gets to know the complete number
*
* @param IBAN the "IBAN ID", i.e. the IBAN or parts of it
* @return fluent setter
*/
@@ -81,9 +88,10 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
return this;
}
/***
* getOwn... methods will be removed in the future in favor of Tradeparty (e.g. Sender) class
* */
/*
I'd really like to get rid of all those getOwn... methods some time but in this case they are in the interface :-(
*/
@Override
@Deprecated
@JsonIgnore
@@ -101,11 +109,12 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
/**
* set Holder
*
* @param name account name (usually account holder if != sender)
* @return fluent setter
*/
public BankDetails setAccountName(String name) {
accountName=name;
accountName = name;
return this;
}
@@ -115,5 +124,4 @@ public class BankDetails implements IZUGFeRDTradeSettlementPayment {
}
}

View File

@@ -0,0 +1,73 @@
// Copyright (c) 2023 Jochen Stärk, see LICENSE file
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.TransactionCalculator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.math.BigDecimal;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class CalculatedInvoice extends Invoice implements Serializable {
protected BigDecimal lineTotalAmount=null;
protected BigDecimal duePayable=null;
protected BigDecimal grandTotal=null;
protected BigDecimal taxBasis=null;
public void calculate() {
TransactionCalculator tc=new TransactionCalculator(this);
grandTotal=tc.getGrandTotal();
lineTotalAmount=tc.getValue();
duePayable=tc.getDuePayable();
taxBasis= tc.getTaxBasis();
}
public BigDecimal getGrandTotal() {
if (grandTotal==null) {
calculate();
}
return grandTotal;
}
public CalculatedInvoice setGrandTotal(BigDecimal grand) {
grandTotal=grand;
return this;
}
public BigDecimal getTaxBasis() {
if (taxBasis==null) {
calculate();
}
return taxBasis;
}
public CalculatedInvoice setTaxBasis(BigDecimal basis) {
taxBasis=basis;
return this;
}
public BigDecimal getDuePayable() {
if (duePayable==null) {
calculate();
}
return duePayable;
}
public CalculatedInvoice setDuePayable(BigDecimal due) {
duePayable=due;
return this;
}
public BigDecimal getLineTotalAmount() {
if (lineTotalAmount==null) {
calculate();
}
return lineTotalAmount;
}
public CalculatedInvoice setLineTotalAmount(BigDecimal total) {
lineTotalAmount=total;
return this;
}
}

View File

@@ -1,5 +1,7 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IZUGFeRDCashDiscount;
import java.math.BigDecimal;
@@ -7,6 +9,8 @@ import java.math.BigDecimal;
/***
* A class to represent discounts for early payments ("Skonto")
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class CashDiscount implements IZUGFeRDCashDiscount {
/***
@@ -31,6 +35,31 @@ public class CashDiscount implements IZUGFeRDCashDiscount {
this.days = days;
}
/***
* bean contructor
*/
public CashDiscount() {
}
public BigDecimal getPercent() {
return percent;
}
public CashDiscount setPercent(BigDecimal percent) {
this.percent = percent;
return this;
}
public Integer getDays() {
return days;
}
public CashDiscount setDays(Integer days) {
this.days = days;
return this;
}
/***
* @return this particular cash discount as cross industry invoice XML
*/

View File

@@ -1,5 +1,8 @@
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.IAbsoluteValueProvider;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
@@ -8,6 +11,8 @@ import java.math.BigDecimal;
/***
* Absolute and relative charges for document and item level
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Charge implements IZUGFeRDAllowanceCharge {
/**
@@ -151,6 +156,7 @@ public class Charge implements IZUGFeRDAllowanceCharge {
* @return true since it is supposed to be calculated negatively
*/
@Override
@JsonIgnore
public boolean isCharge() {
return true;
}

View File

@@ -20,15 +20,19 @@
*/
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* A schemed classification for products. The scheme can be anything defined in UNTDID 7143.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class ClassCode {
private final String listID;
private final String code;
private String listID;
private String code;
private String listVersionID;
/**
@@ -54,6 +58,13 @@ public class ClassCode {
this(listID, code, null);
}
/***
* bean constructor
*/
public ClassCode() {
}
/***
* Set the version for the scheme returned by {@link #getListID()}
* @param listVersionID the scheme version

View File

@@ -1,6 +1,7 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@@ -11,6 +12,7 @@ import org.w3c.dom.NodeList;
* @see TradeParty
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Contact implements IZUGFeRDExportableContact {
/**

View File

@@ -20,14 +20,18 @@
*/
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IDesignatedProductClassification;
/**
* An implementation of {@link IDesignatedProductClassification} for describing a {@link org.mustangproject.Product}
*
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class DesignatedProductClassification implements IDesignatedProductClassification {
private final ClassCode classCode;
private ClassCode classCode;
private String className;
/**
@@ -50,6 +54,13 @@ public class DesignatedProductClassification implements IDesignatedProductClassi
this(classCode, null);
}
/**
* Bean constructor for schemed product descriptor
*/
public DesignatedProductClassification() {
classCode = null;// we need this constructor for jackson, i.e. to be able to JSON
}
@Override
public ClassCode getClassCode() {
return classCode;

View File

@@ -1,20 +1,32 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IZUGFeRDTradeSettlementDebit;
/**
* provides e.g. the IBAN to transfer money to :-)
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class DirectDebit implements IZUGFeRDTradeSettlementDebit {
/**
* Debited account identifier (BT-91)
*/
protected final String IBAN;
protected String IBAN;
/**
* Mandate reference identifier (BT-89)
*/
protected final String mandate;
protected String mandate;
/**
* bean constructor
*/
public DirectDebit() {
this.IBAN = "";
this.mandate = "";
}
/***
* constructor for normal use :-)
@@ -35,8 +47,18 @@ public class DirectDebit implements IZUGFeRDTradeSettlementDebit {
return this.IBAN;
}
public DirectDebit setIBAN(String iBAN) {
this.IBAN = iBAN;
return this;
}
@Override
public String getMandate() {
return this.mandate;
}
public DirectDebit setMandate(String mandate) {
this.mandate = mandate;
return this;
}
}

View File

@@ -0,0 +1,16 @@
package org.mustangproject.Exceptions;
import java.text.ParseException;
/***
* will be thrown if an invoice cant be reproduced numerically
*/
public class ArithmetricException extends ParseException {
public ArithmetricException() {
this("");
}
public ArithmetricException(String details) {
super("Could not reproduce the invoice. " + details, 0);
}
}

View File

@@ -0,0 +1,12 @@
package org.mustangproject.Exceptions;
import java.text.ParseException;
/***
* will be thrown if a invoice cant be read
*/
public class StructureException extends ParseException {
public StructureException(String message, int line) {
super(message, line);
}
}

View File

@@ -1,5 +1,10 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class FileAttachment {
protected String filename;
@@ -8,12 +13,20 @@ public class FileAttachment {
protected String description;
protected byte[] data;
/***
* bean contructor
*/
public FileAttachment() {
}
public FileAttachment(String filename, String mimetype, String relation, byte[] data) {
this.filename = filename;
this.mimetype = mimetype;
this.relation = relation;
this.data = data;
description = "Additional file attachment";
this.description = "Additional file attachment";
}
public String getDescription() {
@@ -60,8 +73,4 @@ public class FileAttachment {
this.data = data;
return this;
}
}

View File

@@ -1,68 +1,100 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
/**
* A grouping of business terms to indicate accounting-relevant free texts including a qualification of these.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class IncludedNote {
private final String content;
private final SubjectCode subjectCode;
private String content;
private static final String INCLUDE_START = "<ram:IncludedNote>";
private static final String INCLUDE_END = "</ram:IncludedNote>";
private static final String CONTENT_START = "<ram:Content>";
private static final String CONTENT_END = "</ram:Content>";
private static final String SUBJECT_CODE_START = "<ram:SubjectCode>";
private static final String SUBJECT_CODE_END = "</ram:SubjectCode>";
private SubjectCode subjectCode;
private IncludedNote(String content, SubjectCode subjectCode) {
this.content = content;
this.subjectCode = subjectCode;
}
private static final String INCLUDE_START = "<ram:IncludedNote>";
private static final String INCLUDE_END = "</ram:IncludedNote>";
private static final String CONTENT_START = "<ram:Content>";
private static final String CONTENT_END = "</ram:Content>";
private static final String SUBJECT_CODE_START = "<ram:SubjectCode>";
private static final String SUBJECT_CODE_END = "</ram:SubjectCode>";
public static IncludedNote generalNote(String content) {
return new IncludedNote(content, SubjectCode.AAI);
}
public static IncludedNote regulatoryNote(String content) {
return new IncludedNote(content, SubjectCode.REG);
}
public static IncludedNote legalNote(String content) {
return new IncludedNote(content, SubjectCode.ABL);
}
public static IncludedNote customsNote(String content) {
return new IncludedNote(content, SubjectCode.CUS);
}
public static IncludedNote sellerNote(String content) {
return new IncludedNote(content, SubjectCode.SUR);
}
public static IncludedNote taxNote(String content) {
return new IncludedNote(content, SubjectCode.TXD);
}
public static IncludedNote introductionNote(String content) {
return new IncludedNote(content, SubjectCode.ACY);
}
public static IncludedNote discountBonusNote(String content) {
return new IncludedNote(content, SubjectCode.AAK);
}
public IncludedNote(String content, SubjectCode subjectCode) {
this.content = content;
this.subjectCode = subjectCode;
}
public static IncludedNote unspecifiedNote(String content) {
return new IncludedNote(content, null);
}
/**
* bean constructor
*/
public IncludedNote() {
public String getContent() {
return content;
}
}
public static IncludedNote generalNote(String content) {
return new IncludedNote(content, SubjectCode.AAI);
}
public static IncludedNote regulatoryNote(String content) {
return new IncludedNote(content, SubjectCode.REG);
}
public static IncludedNote legalNote(String content) {
return new IncludedNote(content, SubjectCode.ABL);
}
public static IncludedNote customsNote(String content) {
return new IncludedNote(content, SubjectCode.CUS);
}
public static IncludedNote sellerNote(String content) {
return new IncludedNote(content, SubjectCode.SUR);
}
public static IncludedNote taxNote(String content) {
return new IncludedNote(content, SubjectCode.TXD);
}
public static IncludedNote introductionNote(String content) {
return new IncludedNote(content, SubjectCode.ACY);
}
public static IncludedNote discountBonusNote(String content) {
return new IncludedNote(content, SubjectCode.AAK);
}
public static IncludedNote unspecifiedNote(String content) {
return new IncludedNote(content, null);
}
public String getContent() {
return content;
}
public SubjectCode getSubjectCode() {
return subjectCode;
}
public IncludedNote setSubjectCode(SubjectCode subjectCode) {
this.subjectCode = subjectCode;
return this;
}
public IncludedNote setContent(String content) {
this.content = content;
return this;
}
public String toCiiXml() {
String result = INCLUDE_START + CONTENT_START +
XMLTools.encodeXML(getContent()) + CONTENT_END;
if (getSubjectCode() != null) {
result += SUBJECT_CODE_START + getSubjectCode() + SUBJECT_CODE_END;
}
return result + INCLUDE_END;
}
public SubjectCode getSubjectCode() {
return subjectCode;
}
public String toCiiXml(){
String result = INCLUDE_START + CONTENT_START +
XMLTools.encodeXML(getContent() )+ CONTENT_END;
if (getSubjectCode() != null) {
result += SUBJECT_CODE_START + getSubjectCode() + SUBJECT_CODE_END;
}
return result + INCLUDE_END;
}
}

View File

@@ -21,11 +21,9 @@
package org.mustangproject;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.*;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
@@ -37,9 +35,10 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
* @see IExportableTransaction if you want to implement an interface instead
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Invoice implements IExportableTransaction {
protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, invoiceReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null;
protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null;
protected Date issueDate = null, dueDate = null, deliveryDate = null;
protected TradeParty sender = null, recipient = null, deliveryAddress = null, payee = null;
protected ArrayList<CashDiscount> cashDiscounts = null;
@@ -58,12 +57,18 @@ public class Invoice implements IExportableTransaction {
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>(),
Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>();
protected IZUGFeRDPaymentTerms paymentTerms = null;
protected String invoiceReferencedDocumentID = null;
protected Date invoiceReferencedIssueDate;
// New field for storing Invoiced Object Identifier (BG-3)
protected ArrayList<ReferencedDocument> invoiceReferencedDocuments = null;
protected String specifiedProcuringProjectID = null;
protected String specifiedProcuringProjectName = null;
protected String despatchAdviceReferencedDocumentID = null;
protected String vatDueDateTypeCode = null;
protected String creditorReferenceID; // required when direct debit is used.
private BigDecimal roundingAmount=null;
public Invoice() {
ZFItems = new ArrayList<>();
@@ -113,6 +118,16 @@ public class Invoice implements IExportableTransaction {
}
/***
* setter in case e.g. jackson tries to map attachments (normal use embedFileInXML)
* @param fileArr Array of FileAttachments
* @return fluent setter
*/
public Invoice setAdditionalReferencedDocuments(FileAttachment[] fileArr) {
xmlEmbeddedFiles = new ArrayList<>(Arrays.asList(fileArr));
return this;
}
@Override
public IZUGFeRDCashDiscount[] getCashDiscounts() {
return cashDiscounts.toArray(new IZUGFeRDCashDiscount[0]);
@@ -138,6 +153,7 @@ public class Invoice implements IExportableTransaction {
*/
public Invoice setCorrection(String number) {
setInvoiceReferencedDocumentID(number);
addInvoiceReferencedDocument(new ReferencedDocument(number));
documentCode = DocumentCodeTypeConstants.CORRECTEDINVOICE;
return this;
}
@@ -410,6 +426,11 @@ public class Invoice implements IExportableTransaction {
return includedNotes;
}
public Invoice setNotesWithSubjectCode(List<IncludedNote> theList) {
includedNotes=theList;
return this;
}
@Override
public String getCurrency() {
return currency;
@@ -465,6 +486,26 @@ public class Invoice implements IExportableTransaction {
return sender;
}
/***
* for currency rounding differences to 5ct e.g. in Netherlands ("Rappenrundung")
* @return null if not set, otherwise BigDecimal of Euros
*/
@Override
public BigDecimal getRoundingAmount() {
return roundingAmount;
}
/***
* set the cent e.g. to reach the next 5ct mark for currencies in certain countries
* e.g. in the Netherlands ("Rappenrundung")
* @param amount
* @return fluent setter
*/
public Invoice setRoundingAmount(BigDecimal amount) {
roundingAmount=amount;
return this;
}
/***
* sets a named sender contact
* @deprecated use setSender
@@ -511,6 +552,26 @@ public class Invoice implements IExportableTransaction {
return this;
}
// Getter for BG-3
@Override
public ArrayList<ReferencedDocument> getInvoiceReferencedDocuments() {
return invoiceReferencedDocuments;
}
// Setter for BG-3
public void setInvoiceReferencedDocuments(ArrayList<ReferencedDocument> invoiceReferencedDocuments) {
this.invoiceReferencedDocuments = invoiceReferencedDocuments;
}
// Method to add a single ReferencedDocument for BG-3
public Invoice addInvoiceReferencedDocument(ReferencedDocument doc) {
if (invoiceReferencedDocuments == null) {
invoiceReferencedDocuments = new ArrayList<>();
}
invoiceReferencedDocuments.add(doc);
return this;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFAllowances() {
if (Allowances.isEmpty()) {
@@ -520,6 +581,20 @@ public class Invoice implements IExportableTransaction {
}
}
/***
* this is wrong and only used from jackson
* @param iza the Array of allowances/charges
* @return fluent setter
*/
public Invoice setZFAllowances(Allowance[] iza) {
Allowances=new ArrayList<>();
for (IZUGFeRDAllowanceCharge cz:iza) {
Allowances.add(cz);
}
return this;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFCharges() {
@@ -530,6 +605,18 @@ public class Invoice implements IExportableTransaction {
}
}
/***
* this is wrong and only used from jackson
* @param iza the array of charges
* @return fluent setter
*/
public Invoice setZFCharges(Charge[] iza) {
Charges=new ArrayList<>();
for (IZUGFeRDAllowanceCharge cz:iza) {
Charges.add(cz);
}
return this;
}
@Override
public IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges() {

View File

@@ -1,6 +1,7 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IReferencedDocument;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
@@ -11,13 +12,18 @@ import org.w3c.dom.NodeList;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
/***
* describes any invoice line
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Item implements IZUGFeRDExportableItem {
protected BigDecimal price = BigDecimal.ZERO;
protected BigDecimal quantity;
@@ -35,6 +41,8 @@ public class Item implements IZUGFeRDExportableItem {
protected ArrayList<ReferencedDocument> additionalReference = null;
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>();
protected ArrayList<IZUGFeRDAllowanceCharge> Charges = new ArrayList<>();
protected List<IncludedNote> includedNotes = null;
//protected HashMap<String, String> attributes = new HashMap<>();
/***
* default constructor
@@ -62,11 +70,39 @@ public class Item implements IZUGFeRDExportableItem {
// ubl
//we need: name description unitcode
//and we additionally have vat%
setProduct(new Product());
// Bharti's homework 20241126:Streams https://www.youtube.com/watch?v=Lf01cBzmuXw
// and Lambdas https://www.youtube.com/watch?v=HCyx31NW8xg
setProduct(new Product(itemMap.getNode("Item").get()));
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("BuyersItemIdentification").ifPresent(BuyersItemIdentification -> {
BuyersItemIdentification.getAsString("ID").ifPresent(product::setBuyerAssignedID);
});
// String name = icnm.getAsStringOrNull("Name");
// String val = icnm.getAsStringOrNull("Value");
// if (name != null && val != null) {
// if (attributes == null) {
// attributes = new HashMap<>();
// }
// product.attributes.put(name, val);
// }
//icnm.getNode("AdditionalItemProperty").flatMap(n ->n.getAttributes()).ifPresent(product::setAttributes);
icnm.getAsNodeMap("ClassifiedTaxCategory").flatMap(m -> m.getAsBigDecimal("Percent"))
.ifPresent(product::setVATPercent);
});
itemMap.getAsNodeMap("AssociatedDocumentLineDocument").ifPresent(icnm -> {
icnm.getAsString("LineID").ifPresent(this::setId);
});
itemMap.getAsNodeMap("Price").ifPresent(icnm -> {
// ubl
@@ -81,21 +117,43 @@ public class Item implements IZUGFeRDExportableItem {
product.setUnit(icn.getAttributes().getNamedItem("unitCode").getNodeValue());
});
itemMap.getAllNodes("DocumentReference").map(ReferencedDocument::fromNode)
.forEach(this::addAdditionalReference);
// ubl
itemMap.getAsNodeMap("OrderLineReference")
// ubl
.flatMap(bordNodes -> bordNodes.getAsString("LineID"))
.ifPresent(this::addReferencedLineID);
itemMap.getAsString("ID")
.ifPresent(this::setId);
itemMap.getAsString("Note")
.ifPresent(this::addNote);
itemMap.getAsNodeMap("SpecifiedLineTradeAgreement", "SpecifiedSupplyChainTradeAgreement").ifPresent(icnm -> {
icnm.getAsNodeMap("BuyerOrderReferencedDocument")
.flatMap(bordNodes -> bordNodes.getAsString("LineID"))
.ifPresent(this::addReferencedLineID);
icnm.getAsNodeMap("NetPriceProductTradePrice").ifPresent(npptpNodes -> {
npptpNodes.getAsBigDecimal("ChargeAmount").ifPresent(this::setPrice);
npptpNodes.getAsBigDecimal("BasisQuantity").ifPresent(this::setBasisQuantity);
});
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode)
.forEach(this::addReferencedDocument);
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).
forEach(this::addReferencedDocument);
});
itemMap.getNode("SpecifiedTradeProduct").map(Product::new).ifPresent(this::setProduct);
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")
@@ -123,6 +181,37 @@ public class Item implements IZUGFeRDExportableItem {
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).forEach(this::addAdditionalReference);
});
itemMap.getAsNodeMap("AssociatedDocumentLineDocument").ifPresent(adld -> {
List<IncludedNote> includedNotes = new ArrayList<>();
adld.getAllNodes("IncludedNote").forEach(item -> {
String subjectCode = "";
String content = null;
NodeList includedNodeChilds = item.getChildNodes();
for (int issueDateChildIndex = 0; issueDateChildIndex < includedNodeChilds.getLength(); issueDateChildIndex++) {
if ((includedNodeChilds.item(issueDateChildIndex).getLocalName() != null)
&& (includedNodeChilds.item(issueDateChildIndex).getLocalName().equals("Content"))) {
content = XMLTools.trimOrNull(includedNodeChilds.item(issueDateChildIndex));
}
if ((includedNodeChilds.item(issueDateChildIndex).getLocalName() != null)
&& (includedNodeChilds.item(issueDateChildIndex).getLocalName().equals("SubjectCode"))) {
subjectCode = XMLTools.trimOrNull(includedNodeChilds.item(issueDateChildIndex));
}
}
boolean foundCode = false;
for (SubjectCode code : SubjectCode.values()) {
if (code.toString().equals(subjectCode)) {
includedNotes.add(new IncludedNote(content, code));
foundCode = true;
break;
}
}
if (!foundCode) {
includedNotes.add(new IncludedNote(content, null));
}
});
addNotes(includedNotes);
});
}
public Item addReferencedLineID(String s) {
@@ -143,6 +232,11 @@ public class Item implements IZUGFeRDExportableItem {
return lineTotalAmount;
}
public Item setNotesWithSubjectCode(List<IncludedNote> theList) {
includedNotes=theList;
return this;
}
/**
* should only be set by calculator classes or maybe when reading from XML
*
@@ -258,7 +352,7 @@ public class Item implements IZUGFeRDExportableItem {
/***
* Adds a item level addition to the price (will be multiplied by quantity)
* @see org.mustangproject.Charge
* @see Charge
* @param izac a relative or absolute charge
* @return fluent setter
*/
@@ -269,7 +363,7 @@ public class Item implements IZUGFeRDExportableItem {
/***
* Adds a item level reduction the price (will be multiplied by quantity)
* @see org.mustangproject.Allowance
* @see Allowance
* @param izac a relative or absolute allowance
* @return fluent setter
*/
@@ -288,6 +382,26 @@ public class Item implements IZUGFeRDExportableItem {
notes = new ArrayList<>();
}
notes.add(text);
addNote(IncludedNote.unspecifiedNote(text));
return this;
}
/***
* adds categorized item level freetext fields (includednote)
* @param theNote IncludedNote to add
* @return fluent setter
*/
public Item addNote(IncludedNote theNote) {
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.add(theNote);
return this;
}
@@ -314,7 +428,7 @@ public class Item implements IZUGFeRDExportableItem {
/***
* adds item level references along with their typecodes and issuerassignedIDs (contract ID, cost centre, ...)
* adds item level references along with their typecodes and issuerassignedIDs (contract ID, cost centre, ...)
* @param doc the ReferencedDocument to add
* @return fluent setter
*/
@@ -333,8 +447,8 @@ public class Item implements IZUGFeRDExportableItem {
}
return additionalReference.toArray(new IReferencedDocument[0]);
}
/***
* specify a item level delivery period
* (apart from the document level delivery period, and the document level
@@ -370,4 +484,19 @@ public class Item implements IZUGFeRDExportableItem {
return detailedDeliveryPeriodTo;
}
public IZUGFeRDExportableItem addNotes(Collection<IncludedNote> notes) {
if (notes == null) {
return this;
}
if (includedNotes == null) {
includedNotes = new ArrayList<>();
}
includedNotes.addAll(notes);
return this;
}
@Override
public List<IncludedNote> getNotesWithSubjectCode() {
return includedNotes;
}
}

View File

@@ -1,6 +1,7 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.*;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@@ -9,6 +10,7 @@ import org.w3c.dom.NodeList;
* A organisation, i.e. usually a company
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class LegalOrganisation implements IZUGFeRDLegalOrganisation {
protected SchemedID schemedID = null;

View File

@@ -1,10 +1,13 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonSetter;
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;
@@ -17,17 +20,20 @@ import java.util.Map;
* describes a product, good or service used in an invoice item line
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Product implements IZUGFeRDExportableProduct {
protected String unit, name, sellerAssignedID, buyerAssignedID;
protected String description="";
protected String taxExemptionReason=null;
protected String taxCategoryCode=null;
protected String description = "";
protected String taxExemptionReason = null;
protected String taxCategoryCode = null;
protected BigDecimal VATPercent;
protected boolean isReverseCharge = false;
protected boolean isIntraCommunitySupply = false;
protected SchemedID globalId = null;
protected String countryOfOrigin = null;
protected HashMap<String, String> attributes = new HashMap<>();
protected List<IDesignatedProductClassification> classifications = new ArrayList<>();
/***
@@ -56,11 +62,13 @@ public class Product implements IZUGFeRDExportableProduct {
}
});
nodeMap.getAsString("SellerAssignedID").ifPresent(this::setSellerAssignedID);
nodeMap.getAsString("BuyerAssignedID").ifPresent(this::setBuyerAssignedID);
nodeMap.getAsString("Name").ifPresent(this::setName);
nodeMap.getAsString("Description").ifPresent(this::setDescription);
nodeMap.getAsNodeMap("ApplicableProductCharacteristic").ifPresent(apcNodes -> {
String key = apcNodes.getAsStringOrNull("Description");
String value = apcNodes.getAsStringOrNull("Value");
@@ -72,6 +80,26 @@ public class Product implements IZUGFeRDExportableProduct {
}
});
//UBL
nodeMap.getAsNodeMap("AdditionalItemProperty").ifPresent(aipNodes -> {
String name = aipNodes.getAsStringOrNull("Name");
String val = aipNodes.getAsStringOrNull("Value");
if (name != null && val != null) {
if (attributes == null) {
attributes = new HashMap<>();
}
attributes.put(name, val);
}
});
nodeMap.getAsNodeMap("CommodityClassification").ifPresent(dpcNodes -> {
String className = dpcNodes.getAsStringOrNull("ClassName");
dpcNodes.getNode("ItemClassificationCode").map(ClassCode::fromNode).ifPresent(classCode ->
classifications.add(new DesignatedProductClassification(classCode, className)));
});
//UBL
nodeMap.getAsNodeMap("DesignatedProductClassification").ifPresent(dpcNodes -> {
String className = dpcNodes.getAsStringOrNull("ClassName");
dpcNodes.getNode("ClassCode").map(ClassCode::fromNode).ifPresent(classCode ->
@@ -112,6 +140,7 @@ public class Product implements IZUGFeRDExportableProduct {
return this;
}
/***
*
* @return e.g. intra-commnunity supply or small business
@@ -126,7 +155,7 @@ public class Product implements IZUGFeRDExportableProduct {
* @param taxExemptionReasonText String e.g. Kleinunternehmer gemäß §19 UStG https://github.com/ZUGFeRD/mustangproject/issues/463
* @return fluent setter
*/
public Product setTaxExemptionReason(String taxExemptionReasonText) {
public Product setTaxExemptionReason(String taxExemptionReasonText) {
taxExemptionReason = taxExemptionReasonText;
return this;
}
@@ -148,7 +177,7 @@ public class Product implements IZUGFeRDExportableProduct {
* @param code e.g. S (normal tax), Z=zero rated, E (e.g. small business) or K (intrra community supply) see also https://github.com/ZUGFeRD/mustangproject/issues/463
* @return fluent setter
*/
public Product setTaxCategoryCode(String code) {
public Product setTaxCategoryCode(String code) {
taxCategoryCode = code;
return this;
}
@@ -275,18 +304,22 @@ public class Product implements IZUGFeRDExportableProduct {
* @return fluent setter
*/
public Product setVATPercent(BigDecimal VATPercent) {
this.VATPercent = VATPercent;
if (VATPercent == null) {
this.VATPercent = BigDecimal.ZERO;
} else {
this.VATPercent = VATPercent;
}
return this;
}
@Override
public String getCountryOfOrigin() {
return this.countryOfOrigin;
return this.countryOfOrigin;
}
public Product setCountryOfOrigin(String countryOfOrigin) {
this.countryOfOrigin = countryOfOrigin;
return this;
this.countryOfOrigin = countryOfOrigin;
return this;
}
@Override
@@ -299,16 +332,16 @@ public class Product implements IZUGFeRDExportableProduct {
}
public Product setAttributes(Map<String, String> attributes) {
this.attributes.clear();
this.attributes.clear();
if (attributes != null) {
this.attributes.putAll(attributes);
}
return this;
return this;
}
public Product addAttribute(String name, String value ) {
this.attributes.put(name, value);
return this;
public Product addAttribute(String name, String value) {
this.attributes.put(name, value);
return this;
}
@Override
@@ -334,6 +367,23 @@ public class Product implements IZUGFeRDExportableProduct {
return this;
}
/**
* Provide Jackson a hint as to use DesignatedProductClassification for the
* IDesignatedProductClassification product classifications
*
* @param classifications the new set of classifications
* @return fluent setter
*/
@JsonSetter("classifications")
public Product setClassificationsClass(DesignatedProductClassification[] classifications) {
this.classifications.clear();
if (classifications != null) {
this.classifications.addAll(Arrays.asList(classifications));
}
return this;
}
/**
* Add a {@link IDesignatedProductClassification} classification
*

View File

@@ -1,25 +1,44 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.Date;
import org.mustangproject.ZUGFeRD.IReferencedDocument;
import org.mustangproject.util.NodeMap;
import org.w3c.dom.Node;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class ReferencedDocument implements IReferencedDocument {
String issuerAssignedID;
String typeCode;
String referenceTypeCode;
Date formattedIssueDateTime;
public ReferencedDocument(String issuerAssignedID, String typeCode, String referenceTypeCode) {
this.issuerAssignedID = issuerAssignedID;
this(issuerAssignedID);
this.typeCode = typeCode;
this.referenceTypeCode = referenceTypeCode;
}
public ReferencedDocument(String issuerAssignedID, String typeCode, String referenceTypeCode, Date formattedIssueDateTime) {
this(issuerAssignedID, typeCode, referenceTypeCode);
this.formattedIssueDateTime = formattedIssueDateTime;
}
public ReferencedDocument(String issuerAssignedID, String referenceTypeCode) {
this(issuerAssignedID, "916", referenceTypeCode); // additional invoice related document
}
public ReferencedDocument(String issuerAssingedID, Date formattedIssueDateTime) {
this(issuerAssingedID);
this.formattedIssueDateTime = formattedIssueDateTime;
}
public ReferencedDocument(String issuerAssignedID) {
this.issuerAssignedID = issuerAssignedID;
this.typeCode = "916"; // additional invoice related document
this.referenceTypeCode = referenceTypeCode;
}
/***
@@ -46,6 +65,15 @@ public class ReferencedDocument implements IReferencedDocument {
this.referenceTypeCode = referenceTypeCode;
}
/**
* issue date of this line
*
* @param formattedIssueDateTime as Date
*/
public void setFormattedIssueDateTime(Date formattedIssueDateTime) {
this.formattedIssueDateTime = formattedIssueDateTime;
}
@Override
public String getIssuerAssignedID() {
return issuerAssignedID;
@@ -61,13 +89,20 @@ public class ReferencedDocument implements IReferencedDocument {
return referenceTypeCode;
}
@Override
public Date getFormattedIssueDateTime()
{
return formattedIssueDateTime;
}
public static ReferencedDocument fromNode(Node node) {
if (!node.hasChildNodes()) {
return null;
}
NodeMap nodes = new NodeMap(node);
return new ReferencedDocument(nodes.getAsStringOrNull("IssuerAssignedID"),
nodes.getAsStringOrNull("TypeCode"),
nodes.getAsStringOrNull("ReferenceTypeCode"));
return new ReferencedDocument(nodes.getAsStringOrNull("IssuerAssignedID", "ID"),
nodes.getAsStringOrNull("TypeCode", "DocumentTypeCode"),
nodes.getAsStringOrNull("ReferenceTypeCode"),
XMLTools.tryDate(nodes.getAsStringOrNull("FormattedIssueDateTime")));
}
}

View File

@@ -1,5 +1,11 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class SchemedID {
protected String scheme;
protected String id;

View File

@@ -36,5 +36,9 @@ public enum SubjectCode {
/**
* Discount and bonus agreements
*/
AAK
AAK,
/**
* Vehicle licence number
*/
ABZ
}

View File

@@ -2,9 +2,11 @@ package org.mustangproject;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableTradeParty;
import org.mustangproject.ZUGFeRD.IZUGFeRDLegalOrganisation;
@@ -15,13 +17,15 @@ import org.w3c.dom.NodeList;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/***
* A organisation, i.e. usually a company
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class TradeParty implements IZUGFeRDExportableTradeParty {
protected String name, zip, street, location, country;
protected String name, zip, street, location, country, taxScheme;
protected String taxID = null, vatID = null;
protected String ID = null;
protected String description = null;
@@ -60,6 +64,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
}
protected void parseFromUBL(NodeList nodes) {
if (nodes.getLength() > 0) {
@@ -69,8 +74,34 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
if (currentItemNode.getLocalName() != null) {
String currentUBLChild = currentItemNode.getLocalName();
if (currentUBLChild.equals("Party")) {
// if (currentUBLChild.equals("Delivery")) {
// NodeList delivery = currentItemNode.getChildNodes();
// for (int deliveryIndex = 0; deliveryIndex < delivery.getLength(); deliveryIndex++) {
// if (delivery.item(deliveryIndex).getLocalName() != null) {
// Node currentNode = delivery.item(deliveryIndex);
// if (currentNode.getLocalName().equals("DeliveryLocation")) {
// NodeList deliveryLocation = currentNode.getChildNodes();
// for (int deliveryLocationIndex = 0; deliveryLocationIndex < deliveryLocation.getLength(); deliveryLocationIndex++) {
// if (deliveryLocation.item(deliveryLocationIndex).getLocalName() != null) {
// if (deliveryLocation.item(deliveryLocationIndex).getLocalName().equals("ID")) {
// //Node currentNode = partyID.item(partyIDIndex);
// setID(deliveryLocation.item(deliveryLocationIndex).getTextContent());
// if ((deliveryLocation.item(deliveryLocationIndex).getAttributes() != null &&
// (deliveryLocation.item(deliveryLocationIndex).getAttributes().getNamedItem("schemeID") != null))
// ) {
// SchemedID sID = new SchemedID().setScheme(deliveryLocation.item(deliveryLocationIndex).getAttributes().getNamedItem("schemeID").getTextContent());
// addGlobalID(sID);
// }
// }
// }
// }
// }
//
// }
// }
// }
if (currentUBLChild.equals("Party")) {
NodeList party = currentItemNode.getChildNodes();
for (int partyIndex = 0; partyIndex < party.getLength(); partyIndex++) {
if (party.item(partyIndex).getLocalName() != null) {
@@ -88,19 +119,102 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
}
}
}
if (party.item(partyIndex).getLocalName().equals("EndpointID")) {
Node currentNode = party.item(partyIndex);
if ((currentNode.getAttributes() != null &&
(currentNode.getAttributes().getNamedItem("schemeID") != null))
&& (party.item(partyIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("EM"))
) {
setEmail(currentNode.getTextContent());
}
}
if (currentTopElementName.equals("PartyIdentification")) {
NodeList partyID = party.item(partyIndex).getChildNodes();
for (int partyIDIndex = 0; partyIDIndex < partyID.getLength(); partyIDIndex++) {
if (partyID.item(partyIDIndex).getLocalName() != null) {
if (partyID.item(partyIDIndex).getLocalName().equals("ID")) {
Node currentNode = partyID.item(partyIDIndex);
if ((currentNode.getAttributes() != null &&
(currentNode.getAttributes().getNamedItem("schemeID") != null))
) {
SchemedID sID = new SchemedID().setScheme(currentNode.getAttributes().getNamedItem("schemeID").getTextContent()).setId(currentNode.getTextContent());
addGlobalID(sID);
}
else {
setID(currentNode.getTextContent());
}
// UBL only: formally it can have a name as well but BT27 party name *should* be stored in
// so overwrite if one exists
if (currentTopElementName.equals("PartyLegalEntity")) {
NodeList legal = party.item(partyIndex).getChildNodes();
for (int legalChildIndex = 0; legalChildIndex < legal.getLength(); legalChildIndex++) {
if (legal.item(legalChildIndex).getLocalName() != null) {
if (legal.item(legalChildIndex).getLocalName().equals("RegistrationName")) {
setName(legal.item(legalChildIndex).getTextContent());
}
}
}
}
if (currentTopElementName.equals("PartyTaxScheme")) {
NodeList partyTaxScheme = party.item(partyIndex).getChildNodes();
String CompanyId = null;
for (int partyTaxSchemeIndex = 0; partyTaxSchemeIndex < partyTaxScheme.getLength(); partyTaxSchemeIndex++) {
if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName() != null) {
if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName().equals("CompanyID")) {
CompanyId = (partyTaxScheme.item(partyTaxSchemeIndex).getTextContent());
}
if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName().equals("TaxScheme")) {
NodeList taxSchemechilds = partyTaxScheme.item(partyTaxSchemeIndex).getChildNodes();
for (int taxSchemechildsIndex = 0; taxSchemechildsIndex < taxSchemechilds.getLength(); taxSchemechildsIndex++) {
if (taxSchemechilds.item(taxSchemechildsIndex).getLocalName() != null) {
if (taxSchemechilds.item(taxSchemechildsIndex).getTextContent().equals("FC") || (taxSchemechilds.item(taxSchemechildsIndex).getTextContent().equals("NOVAT"))) {
setTaxID(CompanyId);
} else {
setVATID(CompanyId);
}
}
}
}
}
}
}
/*
UBL only: formally it can have a name as well but BT27 party name *should* be stored in
so overwrite if one exists
*/
if (currentTopElementName.equals("PartyLegalEntity")) {
NodeList legal = party.item(partyIndex).getChildNodes();
LegalOrganisation lo = null;
for (int legalChildIndex = 0; legalChildIndex < legal.getLength(); legalChildIndex++) {
if (legal.item(legalChildIndex).getLocalName() != null) {
if (legal.item(legalChildIndex).getLocalName().equals("RegistrationName")) {
if (lo == null) {
lo = new LegalOrganisation();
}
lo.setTradingBusinessName(legal.item(legalChildIndex).getTextContent());
}
if (legal.item(legalChildIndex).getLocalName().equals("CompanyLegalForm")) {
setDescription(legal.item(legalChildIndex).getTextContent());
}
if (legal.item(legalChildIndex).getLocalName().equals("CompanyID")) {
if (lo == null) {
lo = new LegalOrganisation();
}
if (legal.item(legalChildIndex).getAttributes().getNamedItem("schemeID")!=null) {
SchemedID sid = new SchemedID(legal.item(legalChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue(), legal.item(legalChildIndex).getTextContent());
lo.setSchemedID(sid);
}
}
// we dont have that attribute yet in the legalorganisation: CompanyLegalForm
if (lo != null) {
setLegalOrganisation(lo);
}
}
}
}
if (currentTopElementName.equals("PostalAddress")) {
NodeList postal = party.item(partyIndex).getChildNodes();
@@ -148,8 +262,6 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
}
}
}
if (postal.item(postalChildIndex).getLocalName().equals("Name")) {
setName(postal.item(postalChildIndex).getTextContent());
@@ -167,7 +279,6 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
}
}
}
if (currentUBLChild.equals("GlobalID")) {
@@ -181,56 +292,6 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
NodeList contact = nodes.item(nodeIndex).getChildNodes();
setContact(new Contact(contact));
}
if (currentUBLChild.equals("PostalTradeAddress")) {
NodeList postal = nodes.item(nodeIndex).getChildNodes();
for (int postalChildIndex = 0; postalChildIndex < postal.getLength(); postalChildIndex++) {
if (postal.item(postalChildIndex).getLocalName() != null) {
if (postal.item(postalChildIndex).getLocalName().equals("LineOne")) {
setStreet(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("LineTwo")) {
setAdditionalAddress(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("LineThree")) {
setAdditionalAddressExtension(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("CityName")) {
setLocation(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("PostcodeCode")) {
setZIP(postal.item(postalChildIndex).getTextContent());
}
if (postal.item(postalChildIndex).getLocalName().equals("CountryID")) {
setCountry(postal.item(postalChildIndex).getTextContent());
}
}
}
}
if (currentUBLChild.equals("SpecifiedTaxRegistration")) {
NodeList taxChilds = nodes.item(nodeIndex).getChildNodes();
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
if (taxChilds.item(taxChildIndex).getLocalName() != null) {
if ((taxChilds.item(taxChildIndex).getLocalName().equals("ID"))) {
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID") != null) {
Node firstChild = taxChilds.item(taxChildIndex).getFirstChild();
if (firstChild != null) {
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("VA")) {
setVATID(firstChild.getNodeValue());
}
if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("FC")) {
setTaxID(firstChild.getNodeValue());
}
}
}
}
}
}
}
}
}
}
@@ -500,6 +561,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
return this;
}
/**
* (optional)
*
@@ -511,6 +573,15 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
return this;
}
/**
* primarily for invoiceimporter and JSON
*
* @return the list of sepa mandates
*/
public List<DirectDebit> getDebitDetails() {
return debitDetails;
}
@Override
public IZUGFeRDLegalOrganisation getLegalOrganisation() {
return legalOrg;
@@ -670,6 +741,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
return contact;
}
@JsonIgnore
public IZUGFeRDTradeSettlement[] getAsTradeSettlement() {
if (bankDetails.isEmpty() && debitDetails.isEmpty()) {
return null;

View File

@@ -4,9 +4,13 @@ import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.io.IOUtils;
import org.dom4j.io.XMLWriter;
import org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat;
import org.w3c.dom.Node;
public class XMLTools extends XMLWriter {
@Override
@@ -39,10 +43,56 @@ public class XMLTools extends XMLWriter {
}
/**
* returns the value of an node
*
* @param node the Node to get the value from
* @return A String or empty String, if no value was found
*/
public static String getNodeValue(Node node) {
if (node != null && node.getFirstChild() != null) {
return node.getFirstChild().getNodeValue();
}
return "";
}
/**
* tries to convert a String to BigDecimal.
*
* @param nodeValue The value as String
* @return a BigDecimal with the value provides as String or a BigDecimal with value 0.00 if an error occurs
*/
public static BigDecimal tryBigDecimal(String nodeValue) {
try {
return new BigDecimal(nodeValue);
} catch (final Exception e) {
try {
return BigDecimal.valueOf(Float.valueOf(nodeValue));
} catch (final Exception ex) {
return new BigDecimal("0.00");
}
}
}
/**
* tries to convert a Node to a BigDecimal.
*
* @param node The value as String
* @return a BigDecimal with the value provides as String or a BigDecimal with value 0.00 if an error occurs
*/
public static BigDecimal tryBigDecimal(Node node) {
final String nodeValue = XMLTools.getNodeValue(node);
if (nodeValue.isEmpty()) {
return null;
}
return XMLTools.tryBigDecimal(nodeValue);
}
/***
* formats a number so that at least minDecimals are displayed but at the maximum maxDecimals are there, i.e.
* cuts potential 0s off the end until minDecimals
* @param value
* @param value the value to be formatted
* @param maxDecimals number of maximal scale
* @param minDecimals number of minimal scale
* @return value as String with decimals in the specified range
@@ -60,7 +110,39 @@ public class XMLTools extends XMLWriter {
}
public static String encodeXML(CharSequence s) {
/***
* returns a util.Date from a 102 String yyyymmdd in a node
* @param node the node
* @return a util.Date, or null, if not parseable
*/
public static Date tryDate(Node node) {
final String nodeValue = XMLTools.getNodeValue(node);
if (nodeValue.isEmpty()) {
return null;
}
return tryDate(nodeValue);
}
/***
* returns a util.Date from a 102 String yyyymmdd
* @param toParse the string
* @return a util.Date, or null, if not parseable
*/
public static Date tryDate(String toParse) {
final SimpleDateFormat formatter = ZUGFeRDDateFormat.DATE.getFormatter();
try {
return formatter.parse(toParse);
} catch (final Exception e) {
return null;
}
}
/***
* relplaces some entities like &lt; , &gt; and &amp; with their escaped pendant like &amp;lt;
* @param s the string
* @return the "safe" string
*/
public static String encodeXML(CharSequence s) {
if (s == null) {
return "";
}
@@ -132,4 +214,16 @@ public class XMLTools extends XMLWriter {
return IOUtils.toByteArray (fileinput);
}
public static String trimOrNull(Node node) {
if (node != null) {
String textContent = node.getTextContent();
if (textContent != null) {
return textContent.trim();
}
}
return null;
}
}

View File

@@ -30,11 +30,13 @@ package org.mustangproject.ZUGFeRD;
* */
import java.math.BigDecimal;
import java.util.Date;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.mustangproject.FileAttachment;
import org.mustangproject.IncludedNote;
import org.mustangproject.ReferencedDocument;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
/***
@@ -321,6 +323,16 @@ public interface IExportableTransaction {
return false;
}
/**
* get the rounding amount
* (only to be usef for NL whose currency requires a rounding to 5ct)
*
* @return the Bigdecimal
*/
default BigDecimal getRoundingAmount() {
return null;
}
/**
* get BuyerReference (BT-10) an identifier assigned by the buyer and used
* for internal routing. Used for the Leitweg-ID.
@@ -415,13 +427,23 @@ public interface IExportableTransaction {
*
* @return the ID of the document
*/
@Deprecated
default String getInvoiceReferencedDocumentID() {
return null;
}
@Deprecated
default Date getInvoiceReferencedIssueDate() {
return null;
}
/**
* Getter for BG-3
* @return list of documents
*/
default ArrayList<ReferencedDocument> getInvoiceReferencedDocuments() {
return null;
}
/**
* get the issue timestamp of the BuyerOrderReferencedDocument, which sits in

View File

@@ -1,5 +1,7 @@
package org.mustangproject.ZUGFeRD;
import java.util.Date;
public interface IReferencedDocument {
/***
@@ -20,4 +22,12 @@ public interface IReferencedDocument {
*/
String getReferenceTypeCode();
/***
*
* issue date of this line
*
* @return date of the issue
*/
Date getFormattedIssueDateTime();
}

View File

@@ -28,7 +28,9 @@ package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import org.mustangproject.IncludedNote;
import org.mustangproject.Item;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -153,4 +155,21 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
return null;
}
/***
*
* @return the line ID
*/
default String getId() {
return null;
}
/**
* A grouping of business terms to indicate accounting-relevant free texts including a qualification of these.
*
* The information are written to the same xml nodes like {@link #getNotes()} but with explicit subjectCode.
* @return list of the notes
*/
default List<IncludedNote> getNotesWithSubjectCode() {
return null;
}
}

View File

@@ -34,16 +34,30 @@ public class LineCalculator {
}
}
BigDecimal vatPercent = currentItem.getProduct().getVATPercent();
if (vatPercent == null)
BigDecimal vatPercent = null;
if (currentItem.getProduct()!=null) {
vatPercent = currentItem.getProduct().getVATPercent();
}
if (vatPercent == null) {
vatPercent = BigDecimal.ZERO;
}
BigDecimal multiplicator = vatPercent.divide(BigDecimal.valueOf(100));
priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159
price = priceGross.subtract(allowance).add(charge);
itemTotalNetAmount = currentItem.getQuantity().multiply(getPrice()).divide(currentItem.getBasisQuantity(), 18, RoundingMode.HALF_UP)
BigDecimal quantity=BigDecimal.ZERO;
if ((currentItem!=null)&&(currentItem.getQuantity()!=null)) {
quantity=currentItem.getQuantity();
}
// Division/Zero occurred here.
// Used the setScale only because that's also done in getBasisQuantity
BigDecimal basisQuantity = currentItem.getBasisQuantity().compareTo(BigDecimal.ZERO) == 0
? BigDecimal.ONE.setScale(4)
: currentItem.getBasisQuantity();
itemTotalNetAmount = quantity.multiply(getPrice()).divide(basisQuantity, 18, RoundingMode.HALF_UP)
.subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);
}
public BigDecimal getPrice() {

View File

@@ -459,6 +459,19 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
}
xml += "</ram:InvoiceReferencedDocument>";
}
if (trans.getInvoiceReferencedDocuments() != null) {
for (var doc : trans.getInvoiceReferencedDocuments()) {
xml += "<ram:InvoiceReferencedDocument>"
+ "<ram:IssuerAssignedID>"
+ XMLTools.encodeXML(doc.getIssuerAssignedID()) + "</ram:IssuerAssignedID>";
if (doc.getFormattedIssueDateTime() != null) {
xml += "<ram:FormattedIssueDateTime>"
+ DATE.qdtFormat(doc.getFormattedIssueDateTime())
+ "</ram:FormattedIssueDateTime>";
}
xml += "</ram:InvoiceReferencedDocument>";
}
}
xml += "</ram:ApplicableHeaderTradeSettlement>";
// + " <IncludedSupplyChainTradeLineItem>"

View File

@@ -4,13 +4,16 @@ import static java.math.BigDecimal.ZERO;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/***
* The Transactioncalculator e.g. adds the line totals and applies VAT on whole
* invoices
*
*
* @see LineCalculator
*/
public class TransactionCalculator implements IAbsoluteValueProvider {
@@ -27,7 +30,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
/***
* if something had already been paid in advance, this will get it from the
* transaction
*
*
* @return prepaid amount
*/
protected BigDecimal getTotalPrepaid() {
@@ -41,19 +44,19 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
/***
* the invoice total with VAT, allowances and
* charges, WITHOUT considering prepaid amount
*
*
* @return the invoice total including taxes
*/
public BigDecimal getGrandTotal() {
final BigDecimal res = getTaxBasis();
BigDecimal basis = getTaxBasis();
return getVATPercentAmountMap().values().stream().map(VATAmount::getCalculated)
.map(p -> p.setScale(2, RoundingMode.HALF_UP)).reduce(BigDecimal.ZERO, BigDecimal::add).add(res);
.map(p -> p.setScale(2, RoundingMode.HALF_UP)).reduce(BigDecimal.ZERO, BigDecimal::add).add(basis);
}
/***
* returns total of charges for this tax rate
*
*
* @param percent a specific rate, or null for any rate
* @return the total amount
*/
@@ -77,7 +80,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
/***
* returns a (potentially concatenated) string of charge reasons, or "Charges"
* if none are defined
*
*
* @param percent a specific rate, or null for any rate
* @return the space separated String
*/
@@ -91,23 +94,20 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
private String getAllowanceChargeReasonForPercent(BigDecimal percent, IZUGFeRDAllowanceCharge[] charges) {
String res = " ";
if ((charges != null) && (charges.length > 0)) {
for (IZUGFeRDAllowanceCharge currentCharge : charges) {
if ((percent == null) || (currentCharge.getTaxPercent().compareTo(percent) == 0)
&& currentCharge.getReason() != null) {
res += currentCharge.getReason() + " ";
}
}
if (charges == null) {
return "";
}
res = res.substring(0, res.length() - 1);
return res;
return Arrays.stream(charges)
.filter(currentCharge -> (percent == null || currentCharge.getTaxPercent().compareTo(percent) == 0))
.map(IZUGFeRDAllowanceCharge::getReason)
.filter(Objects::nonNull)
.collect(Collectors.joining(" "));
}
/***
* returns a (potentially concatenated) string of allowance reasons, or
* "Allowances", if none are defined
*
*
* @param percent a specific rate, or null for any rate
* @return the space separated String
*/
@@ -122,7 +122,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
/***
* returns total of allowances for this tax rate
*
*
* @param percent a specific rate, or null for any rate
* @return the total amount
*/
@@ -134,25 +134,25 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
/***
* returns the total net value of all items, without document level
* charges/allowances
*
*
* @return item sum
*/
protected BigDecimal getTotal() {
BigDecimal dec = Stream.of(trans.getZFItems()).map(LineCalculator::new)
.map(LineCalculator::getItemTotalNetAmount).reduce(ZERO, BigDecimal::add);
.map(LineCalculator::getItemTotalNetAmount).reduce(ZERO, BigDecimal::add);
return dec;
}
/***
* returns the total net value of the invoice, including charges/allowances on
* document level
*
*
* @return item sum +- charges/allowances
*/
protected BigDecimal getTaxBasis() {
public BigDecimal getTaxBasis() {
return getTotal().add(getChargesForPercent(null).setScale(2, RoundingMode.HALF_UP))
.subtract(getAllowancesForPercent(null).setScale(2, RoundingMode.HALF_UP))
.setScale(2, RoundingMode.HALF_UP);
.subtract(getAllowancesForPercent(null).setScale(2, RoundingMode.HALF_UP))
.setScale(2, RoundingMode.HALF_UP);
}
/**
@@ -167,13 +167,17 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
final String vatDueDateTypeCode = trans.getVATDueDateTypeCode();
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
BigDecimal percent = currentItem.getProduct().getVATPercent();
BigDecimal percent = null;
if (currentItem.getProduct()!=null)
{
percent=currentItem.getProduct().getVATPercent();
}
if (percent != null) {
LineCalculator lc = new LineCalculator(currentItem);
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(),
currentItem.getProduct().getTaxCategoryCode(), vatDueDateTypeCode);
String reasonText=currentItem.getProduct().getTaxExemptionReason();
if (reasonText!=null) {
currentItem.getProduct().getTaxCategoryCode(), vatDueDateTypeCode);
String reasonText = currentItem.getProduct().getTaxExemptionReason();
if (reasonText != null) {
itemVATAmount.setVatExemptionReasonText(reasonText);
}
VATAmount current = hm.get(percent.stripTrailingZeros());
@@ -193,8 +197,8 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
VATAmount theAmount = hm.get(taxPercent.stripTrailingZeros());
if (theAmount == null) {
theAmount = new VATAmount(BigDecimal.ZERO, BigDecimal.ZERO,
currentCharge.getCategoryCode() != null ? currentCharge.getCategoryCode() : "S",
vatDueDateTypeCode);
currentCharge.getCategoryCode() != null ? currentCharge.getCategoryCode() : "S",
vatDueDateTypeCode);
}
theAmount.setBasis(theAmount.getBasis().add(currentCharge.getTotalAmount(this)));
BigDecimal factor = taxPercent.divide(new BigDecimal(100));
@@ -211,8 +215,8 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
VATAmount theAmount = hm.get(taxPercent.stripTrailingZeros());
if (theAmount == null) {
theAmount = new VATAmount(BigDecimal.ZERO, BigDecimal.ZERO,
currentAllowance.getCategoryCode() != null ? currentAllowance.getCategoryCode() : "S",
vatDueDateTypeCode);
currentAllowance.getCategoryCode() != null ? currentAllowance.getCategoryCode() : "S",
vatDueDateTypeCode);
}
theAmount.setBasis(theAmount.getBasis().subtract(currentAllowance.getTotalAmount(this)));
BigDecimal factor = taxPercent.divide(new BigDecimal(100));
@@ -239,4 +243,11 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
return getAllowancesForPercent(null).setScale(2, RoundingMode.HALF_UP);
}
public BigDecimal getDuePayable() {
BigDecimal res = getGrandTotal().subtract(getTotalPrepaid());
if (trans.getRoundingAmount() != null) {
res = res.add(trans.getRoundingAmount());
}
return res;
}
}

View File

@@ -0,0 +1,148 @@
package org.mustangproject.ZUGFeRD;
import org.apache.fop.apps.*;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.fop.configuration.Configuration;
import org.apache.fop.configuration.ConfigurationException;
import org.apache.fop.configuration.DefaultConfigurationBuilder;
import org.apache.xmlgraphics.util.MimeConstants;
import org.mustangproject.ClasspathResolverURIAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.nio.charset.StandardCharsets;
public class ValidationLogVisualizer {
public enum Language {
EN,
FR,
DE
}
static final ClassLoader CLASS_LOADER = ValidationLogVisualizer.class.getClassLoader();
private static final String RESOURCE_PATH = "";
private static final Logger LOGGER = LoggerFactory.getLogger(ValidationLogVisualizer.class);
private TransformerFactory mFactory = null;
private Templates mXsltPDFTemplate = null;
public ValidationLogVisualizer() {
mFactory = new net.sf.saxon.TransformerFactoryImpl();
// fact = TransformerFactory.newInstance();
mFactory.setURIResolver(new ValidationLogVisualizer.ClasspathResourceURIResolver());
}
protected void applyXSLTToPDF(final String xmlContent, final OutputStream PDFOutstream)
throws TransformerException {
Transformer transformer = mXsltPDFTemplate.newTransformer();
transformer.transform(new StreamSource(new StringReader(xmlContent)), new StreamResult(PDFOutstream));
}
protected String toFOP(final String xmlContent)
throws TransformerException {
try {
if (mXsltPDFTemplate == null) {
mXsltPDFTemplate = mFactory.newTemplates(
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/result-pdf.xsl")));
}
} catch (TransformerConfigurationException ex) {
LOGGER.error("Failed to init XSLT templates", ex);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
applyXSLTToPDF(xmlContent, baos);
} catch (Exception e1) {
LOGGER.error("Failed to create PDF", e1);
}
return baos.toString(StandardCharsets.UTF_8);
}
public void toPDF(String xmlLogfileContent, String pdfFilename) {
// the writing part
String result = null;
/* remove file endings so that tests can also pass after checking
out from git with arbitrary options (which may include CSRF changes)
*/
try {
result = this.toFOP(xmlLogfileContent);
} catch ( TransformerException e) {
LOGGER.error("Failed to apply FOP", e);
}
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
Configuration cfg = null;
try {
cfg = cfgBuilder.build(CLASS_LOADER.getResourceAsStream("fop-config.xconf"));
} catch (ConfigurationException e) {
throw new RuntimeException(e);
}
FopFactoryBuilder builder = new FopFactoryBuilder(new File(".").toURI(), new ClasspathResolverURIAdapter()).setConfiguration(cfg);
// Step 1: Construct a FopFactory by specifying a reference to the configuration file
// (reuse if you plan to render multiple documents!)
FopFactory fopFactory = builder.build();
fopFactory.getFontManager().setResourceResolver(
ResourceResolverFactory.createInternalResourceResolver(
new File(".").toURI(),
new ClasspathResolverURIAdapter()));
FOUserAgent userAgent = fopFactory.newFOUserAgent();
userAgent.getRendererOptions().put("pdf-a-mode", "PDF/A-3b");
// Step 2: Set up output stream.
// Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams).
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(pdfFilename))) {
// Step 3: Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out);
// Step 4: Setup JAXP using identity transformer
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(); // identity transformer
// Step 5: Setup input and output for XSLT transformation
// Setup input stream
Source src = new StreamSource(new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8)));
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Step 6: Start XSLT transformation and FOP processing
transformer.transform(src, res);
} catch (FOPException | IOException | TransformerException e) {
LOGGER.error("Failed to create PDF", e);
}
}
private static class ClasspathResourceURIResolver implements URIResolver {
ClasspathResourceURIResolver() {
// Do nothing, just prevents synthetic access warning.
}
@Override
public Source resolve(String href, String base) throws TransformerException {
return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/" + href));
}
}
}

View File

@@ -277,11 +277,11 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
String reason = "";
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung")) || profile == Profiles.getByName("EN16931")) {
reason = "<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>";
}
String reasonCode = "";
if ((allowance.getReasonCode() != null) && (profile == Profiles.getByName("XRechnung"))) {
if (allowance.getReasonCode() != null) {
// only in XRechnung profile
reasonCode = "<ram:ReasonCode>" + allowance.getReasonCode() + "</ram:ReasonCode>";
}
@@ -334,7 +334,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
this.trans = trans;
this.calc = new TransactionCalculator(trans);
boolean hasDueDate = false;
boolean hasDueDate = trans.getDueDate() != null;
final SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy");
String exemptionReason = "";
@@ -401,6 +401,10 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
int lineID = 0;
for (final IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
lineID++;
String lineIDStr = Integer.toString(lineID);
if (currentItem.getId()!=null) {
lineIDStr=currentItem.getId();
}
if (currentItem.getProduct().getTaxExemptionReason() != null) {
exemptionReason = "<ram:ExemptionReason>" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + "</ram:ExemptionReason>";
}
@@ -408,7 +412,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if ((getProfile() != Profiles.getByName("Minimum")) && (getProfile() != Profiles.getByName("BasicWL"))) {
xml += "<ram:IncludedSupplyChainTradeLineItem>" +
"<ram:AssociatedDocumentLineDocument>"
+ "<ram:LineID>" + lineID + "</ram:LineID>"
+ "<ram:LineID>" + lineIDStr + "</ram:LineID>"
+ buildItemNotes(currentItem)
+ "</ram:AssociatedDocumentLineDocument>"
@@ -454,7 +458,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if (currentItem.getProduct().getClassifications() != null && currentItem.getProduct().getClassifications().length > 0) {
for (IDesignatedProductClassification classification : currentItem.getProduct().getClassifications()) {
xml += "<ram:DesignatedProductClassification>"
+ "<ram:ClassCode listId=\"" + XMLTools.encodeXML(classification.getClassCode().getListID()) + "\"";
+ "<ram:ClassCode listId=\"" + XMLTools.encodeXML(classification.getClassCode().getListID()) + "\"";
if (classification.getClassCode().getListVersionID() != null) {
xml += " listVersionID=\"" + XMLTools.encodeXML(classification.getClassCode().getListVersionID()) + "\"";
}
@@ -818,13 +822,18 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
}
if ((trans.getPaymentTerms() == null) && (getProfile() != Profiles.getByName("Minimum")) && ((paymentTermsDescription != null) || (trans.getTradeSettlement() != null) || (hasDueDate))) {
xml += "<ram:SpecifiedTradePaymentTerms>";
if (paymentTermsDescription != null) {
xml += "<ram:Description>" + paymentTermsDescription + "</ram:Description>";
}
if (trans.getDueDate() != null) {
xml += "<ram:DueDateDateTime>" // $NON-NLS-2$
+ DATE.udtFormat(trans.getDueDate())
+ "</ram:DueDateDateTime>";// 20130704
}
if (trans.getTradeSettlement() != null) {
for (final IZUGFeRDTradeSettlement payment : trans.getTradeSettlement()) {
@@ -834,12 +843,6 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
}
if (hasDueDate && (trans.getDueDate() != null)) {
xml += "<ram:DueDateDateTime>" // $NON-NLS-2$
+ DATE.udtFormat(trans.getDueDate())
+ "</ram:DueDateDateTime>";// 20130704
}
xml += "</ram:SpecifiedTradePaymentTerms>";
} else {
xml += buildPaymentTermsXml();
@@ -857,7 +860,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
final String chargesTotalLine = "<ram:ChargeTotalAmount>" + currencyFormat(calc.getChargesForPercent(null)) + "</ram:ChargeTotalAmount>";
xml += "<ram:SpecifiedTradeSettlementHeaderMonetarySummation>";
if (getProfile() != Profiles.getByName("Minimum")) {
if ((getProfile() != Profiles.getByName("Minimum")) && (getProfile() != Profiles.getByName("BASICWL"))) {
xml += "<ram:LineTotalAmount>" + currencyFormat(calc.getTotal()) + "</ram:LineTotalAmount>";
xml += chargesTotalLine
+ allowanceTotalLine;
@@ -866,14 +869,18 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
// //
// currencyID=\"EUR\"
+ "<ram:TaxTotalAmount currencyID=\"" + trans.getCurrency() + "\">"
+ currencyFormat(calc.getGrandTotal().subtract(calc.getTaxBasis())) + "</ram:TaxTotalAmount>"
+ "<ram:GrandTotalAmount>" + currencyFormat(calc.getGrandTotal()) + "</ram:GrandTotalAmount>";
+ currencyFormat(calc.getGrandTotal().subtract(calc.getTaxBasis())) + "</ram:TaxTotalAmount>";
if (trans.getRoundingAmount() != null) {
xml += "<ram:RoundingAmount>" + currencyFormat(trans.getRoundingAmount()) + "</ram:RoundingAmount>";
}
xml += "<ram:GrandTotalAmount>" + currencyFormat(calc.getGrandTotal()) + "</ram:GrandTotalAmount>";
// //
// currencyID=\"EUR\"
if (getProfile() != Profiles.getByName("Minimum")) {
xml += "<ram:TotalPrepaidAmount>" + currencyFormat(calc.getTotalPrepaid()) + "</ram:TotalPrepaidAmount>";
}
xml += "<ram:DuePayableAmount>" + currencyFormat(calc.getGrandTotal().subtract(calc.getTotalPrepaid())) + "</ram:DuePayableAmount>"
xml += "<ram:DuePayableAmount>" + currencyFormat(calc.getDuePayable()) + "</ram:DuePayableAmount>"
+ "</ram:SpecifiedTradeSettlementHeaderMonetarySummation>";
if (trans.getInvoiceReferencedDocumentID() != null) {
xml += "<ram:InvoiceReferencedDocument>"
@@ -886,6 +893,19 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
xml += "</ram:InvoiceReferencedDocument>";
}
if (trans.getInvoiceReferencedDocuments() != null) {
for (var doc : trans.getInvoiceReferencedDocuments()) {
xml += "<ram:InvoiceReferencedDocument>"
+ "<ram:IssuerAssignedID>"
+ XMLTools.encodeXML(doc.getIssuerAssignedID()) + "</ram:IssuerAssignedID>";
if (doc.getFormattedIssueDateTime() != null) {
xml += "<ram:FormattedIssueDateTime>"
+ DATE.qdtFormat(doc.getFormattedIssueDateTime())
+ "</ram:FormattedIssueDateTime>";
}
xml += "</ram:InvoiceReferencedDocument>";
}
}
xml += "</ram:ApplicableHeaderTradeSettlement>";
// + "<IncludedSupplyChainTradeLineItem>\n"

View File

@@ -83,8 +83,9 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
}
protected byte[] filenameToByteArray(String pdfFilename) throws IOException {
FileInputStream fileInputStream = new FileInputStream(pdfFilename);
return inputstreamToByteArray(fileInputStream);
try (FileInputStream fileInputStream = new FileInputStream(pdfFilename)) {
return inputstreamToByteArray(fileInputStream);
}
}
protected byte[] inputstreamToByteArray(InputStream fileInputStream) throws IOException {

View File

@@ -13,92 +13,34 @@ package org.mustangproject.ZUGFeRD;
* @version 1.1.0
* @author jstaerk
*/
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class ZUGFeRDImporter {
public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter {
private static final Logger LOGGER = LoggerFactory.getLogger(ZUGFeRDImporter.class);
/**
* if metadata has been found
*/
protected boolean containsMeta = false;
/**
* map filenames of additional XML files to their contents
*/
private final HashMap<String, byte[]> additionalXMLs = new HashMap<>();
/**
* map filenames of all embedded files in the respective PDF
*/
private final ArrayList<FileAttachment> PDFAttachments = new ArrayList<>();
/**
* Raw XML form of the extracted data - may be directly obtained.
*/
private byte[] rawXML = null;
/**
* XMP metadata
*/
private String xmpString = null; // XMP metadata
/**
* parsed Document
*/
private Document document;
private Integer version;
protected ZUGFeRDImporter() {
//constructor for extending classes
public ZUGFeRDImporter() {
super();
}
public ZUGFeRDImporter(String pdfFilename) {
try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) {
extractLowLevel(bis);
} catch (final IOException e) {
LOGGER.error("Failed to extract ZUGFeRD data", e);
throw new ZUGFeRDExportException(e);
}
public ZUGFeRDImporter(String filename) {
super(filename);
}
public ZUGFeRDImporter(InputStream pdfStream) {
try {
extractLowLevel(pdfStream);
} catch (final IOException e) {
LOGGER.error("Failed to extract ZUGFeRD data", e);
throw new ZUGFeRDExportException(e);
}
public ZUGFeRDImporter(InputStream stream) {
super(stream);
}
@@ -113,169 +55,21 @@ public class ZUGFeRDImporter {
/**
* Extracts a ZUGFeRD invoice from a PDF document represented by an input stream. Errors are reported via exception handling.
*
* @param inStream a inputstream of a pdf file
*/
private void extractLowLevel(InputStream inStream) throws IOException {
BufferedInputStream pdfStream = new BufferedInputStream(inStream);
byte[] pad = new byte[4];
pdfStream.mark(0);
pdfStream.read(pad);
pdfStream.reset();
byte[] pdfSignature = {'%', 'P', 'D', 'F'};
if (Arrays.equals(pad, pdfSignature)) { // we have a pdf
try (PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(pdfStream))) {
// PDDocumentInformation info = doc.getDocumentInformation();
final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
//start
if (doc.getDocumentCatalog() == null || doc.getDocumentCatalog().getMetadata() == null) {
LOGGER.info("no-xmlpart");
return;
}
final InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata();
xmpString = convertStreamToString(XMP);
final PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles();
if (etn == null) {
return;
}
final Map<String, PDComplexFileSpecification> efMap = etn.getNames();
// String filePath = "/tmp/";
if (efMap != null) {
extractFiles(efMap); // see
// https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/
} else {
final List<PDNameTreeNode<PDComplexFileSpecification>> kids = etn.getKids();
if (kids == null) {
return;
}
for (final PDNameTreeNode<PDComplexFileSpecification> node : kids) {
final Map<String, PDComplexFileSpecification> namesL = node.getNames();
extractFiles(namesL);
}
}
}
} else {
// no PDF probably XML
containsMeta = true;
setRawXML(XMLTools.getBytesFromStream(pdfStream));
}
}
private void extractFiles(Map<String, PDComplexFileSpecification> names) throws IOException {
for (final String alias : names.keySet()) {
final PDComplexFileSpecification fileSpec = names.get(alias);
final String filename = fileSpec.getFilename();
/**
* filenames for invoice data (ZUGFeRD v1 and v2, Factur-X)
*/
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")) {
containsMeta = true;
// String embeddedFilename = filePath + filename;
// File file = new File(filePath + filename);
// System.out.println("Writing " + embeddedFilename);
// ByteArrayOutputStream fileBytes=new
// ByteArrayOutputStream();
// FileOutputStream fos = new FileOutputStream(file);
setRawXML(embeddedFile.toByteArray());
// fos.write(embeddedFile.getByteArray());
// fos.close();
}
if (filename.startsWith("additional_data")) {
additionalXMLs.put(filename, embeddedFile.toByteArray());
}
PDFAttachments.add(new FileAttachment(filename, embeddedFile.getSubtype(), "Data", embeddedFile.toByteArray()));
}
}
protected Document getDocument() {
return document;
}
private void setDocument() throws ParserConfigurationException, IOException, SAXException {
final DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
xmlFact.setNamespaceAware(true);
final DocumentBuilder builder = xmlFact.newDocumentBuilder();
final ByteArrayInputStream is = new ByteArrayInputStream(rawXML);
/// is.skip(guessBOMSize(is));
document = builder.parse(is);
}
public void setRawXML(byte[] rawXML) throws IOException {
this.containsMeta = true;
this.rawXML = rawXML;
this.version = null;
try {
setDocument();
} catch (ParserConfigurationException | SAXException e) {
LOGGER.error("Failed to parse XML", e);
throw new ZUGFeRDExportException(e);
}
}
protected String extractString(String xpathStr) {
if (!containsMeta) {
throw new ZUGFeRDExportException("No suitable data/ZUGFeRD file could be found.");
}
final String result;
try {
final Document document = getDocument();
final XPathFactory xpathFact = XPathFactory.newInstance();
final XPath xpath = xpathFact.newXPath();
result = xpath.evaluate(xpathStr, document);
} catch (final XPathExpressionException e) {
LOGGER.error("Failed to evaluate XPath", e);
throw new ZUGFeRDExportException(e);
}
return result;
}
/***
* Wrapper for protected method extractString
* @param xpathStr the xpath expression to be evaluated
* @return the extracted String for the specific path in the document
*/
public String wExtractString(String xpathStr) {
return extractString(xpathStr);
}
////////////////////////////////////
/**
* @return the reference (purpose) the sender specified for this invoice
*/
public String getForeignReference() {
String result = extractString("//*[local-name() = 'ApplicableHeaderTradeSettlement']/*[local-name() = 'PaymentReference']");
if (result == null || result.isEmpty()) {
result = extractString("//*[local-name() = 'ApplicableSupplyChainTradeSettlement']/*[local-name() = 'PaymentReference']");
}
return result;
return importedInvoice.getNumber();
}
/**
* @return the ZUGFeRD Profile
*/
public String getZUGFeRDProfil() {
String guideline = extractString("//*[local-name() = 'GuidelineSpecifiedDocumentContextParameter']//*[local-name() = 'ID']");
if (guideline.contains("xrechnung")) {
return "XRECHNUNG";
@@ -299,21 +93,6 @@ public class ZUGFeRDImporter {
}
}
/**
* @return the Invoice Currency Code
*/
public String getInvoiceCurrencyCode() {
try {
if (getVersion() == 1) {
return extractString("//*[local-name() = 'ApplicableSupplyChainTradeSettlement']//*[local-name() = 'InvoiceCurrencyCode']");
} else {
return extractString("//*[local-name() = 'ApplicableHeaderTradeSettlement']//*[local-name() = 'InvoiceCurrencyCode']");
}
} catch (final Exception e) {
// Exception was already logged
return "";
}
}
/**
* @return the IssuerAssigned ID
@@ -336,57 +115,6 @@ public class ZUGFeRDImporter {
return extractIssuerAssignedID("ContractReferencedDocument");
}
private String extractIssuerAssignedID(String propertyName) {
try {
if (getVersion() == 1) {
return extractString("//*[local-name() = '" + propertyName + "']//*[local-name() = 'ID']");
} else {
return extractString("//*[local-name() = '" + propertyName + "']//*[local-name() = 'IssuerAssignedID']");
}
} catch (final Exception e) {
// Exception was already logged
return "";
}
}
/**
* @return the BuyerTradeParty ID
*/
public String getBuyerTradePartyID() {
return extractString("//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'ID']");
}
/**
* @return the Issue Date()
*/
public String getIssueDate() {
try {
if (getVersion() == 1) {
return extractString("//*[local-name() = 'HeaderExchangedDocument']//*[local-name() = 'IssueDateTime']//*[local-name() = 'DateTimeString']");
} else {
return extractString("//*[local-name() = 'ExchangedDocument']//*[local-name() = 'IssueDateTime']//*[local-name() = 'DateTimeString']");
}
} catch (final Exception e) {
// Exception was already logged
return "";
}
}
public Date getDetailedDeliveryPeriodFrom() {
final String toParse = extractString(
"//*[local-name() = 'ApplicableHeaderTradeSettlement']" +
"//*[local-name() = 'BillingSpecifiedPeriod']" +
"//*[local-name() = 'StartDateTime']//*[local-name() = 'DateTimeString']");
return tryDate(toParse);
}
public Date getDetailedDeliveryPeriodTo() {
final String toParse = extractString(
"//*[local-name() = 'ApplicableHeaderTradeSettlement']" +
"//*[local-name() = 'BillingSpecifiedPeriod']" +
"//*[local-name() = 'EndDateTime']//*[local-name() = 'DateTimeString']");
return tryDate(toParse);
}
/**
* @return the TaxBasisTotalAmount
@@ -470,7 +198,16 @@ public class ZUGFeRDImporter {
* @return the BuyerTradeParty SpecifiedTaxRegistration ID
*/
public String getBuyertradePartySpecifiedTaxRegistrationID() {
return extractString("//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'SpecifiedTaxRegistration']//*[local-name() = 'ID']");
String id = null;
if ((importedInvoice.getRecipient()!=null) && (importedInvoice.getRecipient().getLegalOrganisation()!=null)) {
// this *should* be the official result
id = importedInvoice.getRecipient().getLegalOrganisation().getSchemedID().getID();
}
// but also provide some fallback
if (id == null) {
id = getBuyerTradePartyID();
}
return id;
}
@@ -494,14 +231,14 @@ public class ZUGFeRDImporter {
* @return the BuyerTradeParty Name
*/
public String getBuyerTradePartyName() {
return extractString("//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'Name']");
return importedInvoice.getRecipient().getName();
}
/**
* @return the BuyerTradeParty Name
*/
public String getDeliveryTradePartyName() {
return extractString("//*[local-name() = 'ShipToTradeParty']//*[local-name() = 'Name']");
return importedInvoice.getDeliveryAddress().getName();
}
@@ -525,7 +262,7 @@ public class ZUGFeRDImporter {
* @return the Payment Terms
*/
public String getPaymentTerms() {
return extractString("//*[local-name() = 'SpecifiedTradePaymentTerms']//*[local-name() = 'Description']");
return importedInvoice.getPaymentTermDescription();
}
/**
@@ -548,16 +285,7 @@ public class ZUGFeRDImporter {
* @return the Invoice ID
*/
public String getInvoiceID() {
try {
if (getVersion() == 1) {
return extractString("//*[local-name() = 'HeaderExchangedDocument']//*[local-name() = 'ID']");
} else {
return extractString("//*[local-name() = 'ExchangedDocument']//*[local-name() = 'ID']");
}
} catch (final Exception e) {
// Exception was already logged
return "";
}
return importedInvoice.getNumber();
}
@@ -615,7 +343,18 @@ public class ZUGFeRDImporter {
* @return the sender's account IBAN code
*/
public String getIBAN() {
return extractString("//*[local-name() = 'PayeePartyCreditorFinancialAccount']/*[local-name() = 'IBANID']");
if ((importedInvoice==null)||(importedInvoice.getTradeSettlement()==null)) {
return null;
}
for (IZUGFeRDTradeSettlement settlement : importedInvoice.getTradeSettlement()) {
if (settlement instanceof IZUGFeRDTradeSettlementDebit) {
return ((IZUGFeRDTradeSettlementDebit) settlement).getIBAN();
}
if (settlement instanceof IZUGFeRDTradeSettlementPayment) {
return ((IZUGFeRDTradeSettlementPayment) settlement).getOwnIBAN();
}
}
return null;
}
@@ -628,14 +367,7 @@ public class ZUGFeRDImporter {
* @return the total payable amount
*/
public String getAmount() {
String result = extractString("//*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']/*[local-name() = 'DuePayableAmount']");
if (result == null || result.isEmpty()) {
/* fx/zf would be SpecifiedTradeSettlementMonetarySummation
* but ox is SpecifiedTradeSettlementHeaderMonetarySummation...*/
result = extractString("//*[local-name() = 'GrandTotalAmount']");
}
return result;
return importedInvoice.getGrandTotal().toPlainString();
}
@@ -643,7 +375,60 @@ public class ZUGFeRDImporter {
* @return when the payment is due
*/
public String getDueDate() {
return extractString("//*[local-name() = 'SpecifiedTradePaymentTerms']/*[local-name() = 'DueDateDateTime']/*[local-name() = 'DateTimeString']");
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
return sdf.format(importedInvoice.getDueDate());
}
////////////////////
/**
* @return the Invoice Currency Code
*/
public String getInvoiceCurrencyCode() {
return importedInvoice.getCurrency();
}
private String extractIssuerAssignedID(String propertyName) {
try {
if (getVersion() == 1) {
return extractString("//*[local-name() = '" + propertyName + "']//*[local-name() = 'ID']");
} else {
return extractString("//*[local-name() = '" + propertyName + "']//*[local-name() = 'IssuerAssignedID']");
}
} catch (final Exception e) {
// Exception was already logged
return "";
}
}
/**
* @return the BuyerTradeParty ID
*/
public String getBuyerTradePartyID() {
String id = importedInvoice.getRecipient().getID();
if (id == null) {
// provide some fallback
id = importedInvoice.getRecipient().getVATID();
}
return id;
}
/**
* @return the Issue Date()
*/
public String getIssueDate() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
return sdf.format(importedInvoice.getIssueDate());
}
public Date getDetailedDeliveryPeriodFrom() {
return importedInvoice.getDetailedDeliveryPeriodFrom();
}
public Date getDetailedDeliveryPeriodTo() {
return importedInvoice.getDetailedDeliveryPeriodTo();
}
@@ -691,28 +476,6 @@ public class ZUGFeRDImporter {
}
public EStandard getStandard() throws Exception {
if (!containsMeta) {
throw new Exception("Not yet parsed");
}
final String head = getUTF8();
String rootNode = extractString("local-name(/*)");
if (rootNode.equals("CrossIndustryDocument")) {
return EStandard.zugferd;
} else if (rootNode.equals("Invoice")) {
return EStandard.ubl;
} else if (rootNode.equals("CrossIndustryInvoice")) {
return EStandard.facturx;
} else if (rootNode.equals("SCRDMCCBDACIDAMessageStructure")) {
return EStandard.despatchadvice;
} else if (head.contains("<rsm:SCRDMCCBDACIOMessageStructure")) {
return EStandard.orderx;
}
throw new Exception("ZUGFeRD version could not be determined");
}
public int getVersion() throws Exception {
if (!containsMeta) {
throw new Exception("Not yet parsed");
@@ -736,35 +499,6 @@ public class ZUGFeRDImporter {
}
/**
* @return return UTF8 XML (without BOM) of the invoice
*/
public String getUTF8() {
if (rawXML == null) {
return null;
}
if (rawXML.length < 3) {
return new String(rawXML);
}
final byte[] bomlessData;
if ((rawXML[0] == (byte) 0xEF)
&& (rawXML[1] == (byte) 0xBB)
&& (rawXML[2] == (byte) 0xBF)) {
// I don't like BOMs, lets remove it
bomlessData = new byte[rawXML.length - 3];
System.arraycopy(rawXML, 3, bomlessData, 0,
rawXML.length - 3);
} else {
bomlessData = rawXML;
}
return new String(bomlessData);
}
/**
* Returns the raw XML data as extracted from the ZUGFeRD PDF file.
*
@@ -790,14 +524,6 @@ public class ZUGFeRDImporter {
}
static String convertStreamToString(java.io.InputStream is) {
try {
return IOUtils.toString(is, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* returns an instance of PostalTradeAddress for SellerTradeParty section
*
@@ -809,7 +535,7 @@ public class ZUGFeRDImporter {
try {
if (getVersion() == 1) {
nl = getNodeListByPath("//*[local-name() = 'CrossIndustryDocument']//*[local-name() = 'SpecifiedSupplyChainTradeTransaction']/*[local-name() = 'ApplicableSupplyChainTradeAgreement']//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'PostalTradeAddress']");
nl = getNodeListByPath("//*[localname() = 'CrossIndustryDocument']//*[local-name() = 'SpecifiedSupplyChainTradeTransaction']/*[local-name() = 'ApplicableSupplyChainTradeAgreement']//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'PostalTradeAddress']");
} else {
nl = getNodeListByPath("//*[local-name() = 'CrossIndustryInvoice']//*[local-name() = 'SupplyChainTradeTransaction']//*[local-name() = 'ApplicableHeaderTradeAgreement']//*[local-name() = 'BuyerTradeParty']//*[local-name() = 'PostalTradeAddress']");
}
@@ -929,9 +655,11 @@ public class ZUGFeRDImporter {
/**
* returns a list of LineItems
* @deprecated use invoiceimporter getZFItems
*
* @return a List of LineItem instances
*/
@Deprecated
public List<Item> getLineItemList() {
final List<Node> nodeList = getLineItemNodes();
final List<Item> lineItemList = new ArrayList<>();
@@ -953,7 +681,7 @@ public class ZUGFeRDImporter {
if (node != null) {
final NodeList tradeAgreementChildren = node.getChildNodes();
node = getNodeByName(tradeAgreementChildren, "ChargeAmount");
lineItem.setPrice(tryBigDecimal(getNodeValue(node)));
lineItem.setPrice(XMLTools.tryBigDecimal(node));
node = getNodeByName(tradeAgreementChildren, "BasisQuantity");
if (node != null && node.getAttributes() != null) {
final Node unitCodeAttribute = node.getAttributes().getNamedItem("unitCode");
@@ -966,49 +694,65 @@ public class ZUGFeRDImporter {
node = getNodeByName(nn.getChildNodes(), "GrossPriceProductTradePrice");
if (node != null) {
node = getNodeByName(node.getChildNodes(), "ChargeAmount");
lineItem.setGrossPrice(tryBigDecimal(getNodeValue(node)));
lineItem.setGrossPrice(XMLTools.tryBigDecimal(node));
}
break;
case "AssociatedDocumentLineDocument":
node = getNodeByName(nn.getChildNodes(), "LineID");
lineItem.setId(getNodeValue(node));
lineItem.setId(XMLTools.getNodeValue(node));
break;
case "SpecifiedTradeProduct":
node = getNodeByName(nn.getChildNodes(), "GlobalID");
if (node != null) {
SchemedID globalId = new SchemedID()
.setScheme(node.getAttributes()
.getNamedItem("schemeID").getNodeValue())
.setId(XMLTools.getNodeValue(node));
lineItem.getProduct().addGlobalID(globalId);
}
node = getNodeByName(nn.getChildNodes(), "SellerAssignedID");
lineItem.getProduct().setSellerAssignedID(getNodeValue(node));
lineItem.getProduct().setSellerAssignedID(XMLTools.getNodeValue(node));
node = getNodeByName(nn.getChildNodes(), "BuyerAssignedID");
lineItem.getProduct().setBuyerAssignedID(getNodeValue(node));
lineItem.getProduct().setBuyerAssignedID(XMLTools.getNodeValue(node));
node = getNodeByName(nn.getChildNodes(), "Name");
lineItem.getProduct().setName(getNodeValue(node));
lineItem.getProduct().setName(XMLTools.getNodeValue(node));
node = getNodeByName(nn.getChildNodes(), "Description");
lineItem.getProduct().setDescription(getNodeValue(node));
lineItem.getProduct().setDescription(XMLTools.getNodeValue(node));
break;
case "SpecifiedLineTradeDelivery":
case "SpecifiedSupplyChainTradeDelivery":
node = getNodeByName(nn.getChildNodes(), "BilledQuantity");
lineItem.setQuantity(tryBigDecimal(getNodeValue(node)));
lineItem.setQuantity(XMLTools.tryBigDecimal(node));
break;
case "SpecifiedLineTradeSettlement":
node = getNodeByName(nn.getChildNodes(), "ApplicableTradeTax");
if (node != null) {
node = getNodeByName(node.getChildNodes(), "RateApplicablePercent");
lineItem.getProduct().setVATPercent(tryBigDecimal(getNodeValue(node)));
lineItem.getProduct().setVATPercent(XMLTools.tryBigDecimal(node));
}
node = getNodeByName(nn.getChildNodes(), "ApplicableTradeTax");
if (node != null) {
node = getNodeByName(node.getChildNodes(), "CalculatedAmount");
lineItem.setTax(tryBigDecimal(getNodeValue(node)));
lineItem.setTax(XMLTools.tryBigDecimal(node));
}
node = getNodeByName(nn.getChildNodes(), "ApplicableTradeTax");
if (node != null) {
node = getNodeByName(node.getChildNodes(), "CategoryCode");
if(node != null){
lineItem.getProduct().setTaxCategoryCode(XMLTools.getNodeValue(node));
}
}
node = getNodeByName(nn.getChildNodes(), "BillingSpecifiedPeriod");
if (node != null) {
final Node start = getNodeByName(node.getChildNodes(), "StartDateTime");
@@ -1021,13 +765,13 @@ public class ZUGFeRDImporter {
if (end != null) {
dateTimeEnd = getNodeByName(end.getChildNodes(), "DateTimeString");
}
lineItem.setDetailedDeliveryPeriod(tryDate(dateTimeStart), tryDate(dateTimeEnd));
lineItem.setDetailedDeliveryPeriod(XMLTools.tryDate(dateTimeStart), XMLTools.tryDate(dateTimeEnd));
}
node = getNodeByName(nn.getChildNodes(), "SpecifiedTradeSettlementLineMonetarySummation");
if (node != null) {
node = getNodeByName(node.getChildNodes(), "LineTotalAmount");
lineItem.setLineTotalAmount(tryBigDecimal(getNodeValue(node)));
lineItem.setLineTotalAmount(XMLTools.tryBigDecimal(node));
}
break;
case "SpecifiedSupplyChainTradeSettlement":
@@ -1036,19 +780,19 @@ public class ZUGFeRDImporter {
node = getNodeByName(nn.getChildNodes(), "ApplicableTradeTax");
if (node != null) {
node = getNodeByName(node.getChildNodes(), "ApplicablePercent");
lineItem.getProduct().setVATPercent(tryBigDecimal(getNodeValue(node)));
lineItem.getProduct().setVATPercent(XMLTools.tryBigDecimal(node));
}
node = getNodeByName(nn.getChildNodes(), "ApplicableTradeTax");
if (node != null) {
node = getNodeByName(node.getChildNodes(), "CalculatedAmount");
lineItem.setTax(tryBigDecimal(getNodeValue(node)));
lineItem.setTax(XMLTools.tryBigDecimal(node));
}
node = getNodeByName(nn.getChildNodes(), "SpecifiedTradeSettlementMonetarySummation");
if (node != null) {
node = getNodeByName(node.getChildNodes(), "LineTotalAmount");
lineItem.setLineTotalAmount(tryBigDecimal(getNodeValue(node)));
lineItem.setLineTotalAmount(XMLTools.tryBigDecimal(node));
}
break;
}
@@ -1123,51 +867,4 @@ public class ZUGFeRDImporter {
}
}
/**
* returns the value of an node
*
* @param node the Node to get the value from
* @return A String or empty String, if no value was found
*/
private String getNodeValue(Node node) {
if (node != null && node.getFirstChild() != null) {
return node.getFirstChild().getNodeValue();
}
return "";
}
/**
* tries to convert an String to BigDecimal.
*
* @param nodeValue The value as String
* @return a BigDecimal with the value provides as String or a BigDecimal with value 0.00 if an error occurs
*/
private BigDecimal tryBigDecimal(String nodeValue) {
try {
return new BigDecimal(nodeValue);
} catch (final Exception e) {
try {
return BigDecimal.valueOf(Float.valueOf(nodeValue));
} catch (final Exception ex) {
return new BigDecimal("0.00");
}
}
}
private Date tryDate(Node node) {
final String nodeValue = getNodeValue(node);
if (nodeValue.isEmpty()) {
return null;
}
return tryDate(nodeValue);
}
private static Date tryDate(String toParse) {
final SimpleDateFormat formatter = ZUGFeRDDateFormat.DATE.getFormatter();
try {
return formatter.parse(toParse);
} catch (final Exception e) {
return null;
}
}
}

View File

@@ -20,42 +20,9 @@
*/
package org.mustangproject.ZUGFeRD;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.FopFactoryBuilder;
import com.helger.commons.io.stream.StreamHelper;
import org.apache.commons.io.IOUtils;
import org.apache.fop.apps.*;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.fop.configuration.Configuration;
import org.apache.fop.configuration.ConfigurationException;
@@ -65,12 +32,19 @@ import org.mustangproject.ClasspathResolverURIAdapter;
import org.mustangproject.EStandard;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.helger.commons.io.stream.StreamHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
public class ZUGFeRDVisualizer {
@@ -113,7 +87,7 @@ public class ZUGFeRDVisualizer {
* @param fis inputstream (will be consumed)
* @return (facturx = cii)
*/
public EStandard findOutStandardFromRootNode(InputStream fis) {
private EStandard findOutStandardFromRootNode(InputStream fis) {
String zf1Signature = "CrossIndustryDocument";
String zf2Signature = "CrossIndustryInvoice";
@@ -144,111 +118,108 @@ public class ZUGFeRDVisualizer {
return null;
}
public String visualize(String xmlFilename, Language lang)
throws FileNotFoundException, TransformerException, IOException, SAXException, ParserConfigurationException {
try {
if (mXsltPDFTemplate == null) {
mXsltPDFTemplate = mFactory.newTemplates(
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xr-pdf.xsl")));
}
if (mXsltHTMLTemplate == null) {
mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource(
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html." + lang.name().toLowerCase() + ".xsl")));
}
if (mXsltZF1HTMLTemplate == null) {
mXsltZF1HTMLTemplate = mFactory.newTemplates(new StreamSource(
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt")));
}
} catch (TransformerConfigurationException ex) {
LOGGER.error("Failed to init XSLT templates", ex);
}
/**
* *
* http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf
* http://www.ferd-net.de/upload/Dokumente/FACTUR-X_ZUGFeRD_2p0_Teil1_Profil_EN16931_1p03.pdf
* http://countwordsfree.com/xmlviewer
*/
public String visualize(String xmlFilename, Language lang) throws IOException, TransformerException {
FileInputStream fis = new FileInputStream(xmlFilename);
String fileContent = "";
try {
fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename)), StandardCharsets.UTF_8);
} catch (IOException e2) {
LOGGER.error("Failed to read file content", e2);
}
return visualize(fis, lang);
}
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
public String visualize(InputStream inputXml, Language lang) throws IOException, TransformerException {
initTemplates(lang);
boolean doPostProcessing = false;
String fileContent = new String(IOUtils.toByteArray(inputXml), StandardCharsets.UTF_8);
EStandard thestandard = findOutStandardFromRootNode(new ByteArrayInputStream(fileContent.getBytes(StandardCharsets.UTF_8)));
ByteArrayOutputStream htmlOutput = new ByteArrayOutputStream();
fis = new FileInputStream(xmlFilename); // fis wont reset() so re-read from beginning
EStandard thestandard = findOutStandardFromRootNode(fis);
fis = new FileInputStream(xmlFilename); // fis wont reset() so re-read from beginning
ByteArrayInputStream xmlContentStream = new ByteArrayInputStream(fileContent.getBytes(StandardCharsets.UTF_8));
if (thestandard == EStandard.zugferd) {
applyZF1XSLT(fis, baos);
applyZF1XSLT(xmlContentStream, htmlOutput);
return htmlOutput.toString(StandardCharsets.UTF_8);
} else if (thestandard == EStandard.facturx) {
//zf2 or fx
applyZF2XSLT(fis, iaos);
doPostProcessing = true;
applyZF2XSLT(xmlContentStream, htmlOutput);
} else if (thestandard == EStandard.ubl) {
//zf2 or fx
applyUBL2XSLT(fis, iaos);
doPostProcessing = true;
applyUBL2XSLT(xmlContentStream, htmlOutput);
} else if (thestandard == EStandard.ubl_creditnote) {
//zf2 or fx
applyUBLCreditNote2XSLT(fis, iaos);
doPostProcessing = true;
applyUBLCreditNote2XSLT(xmlContentStream, htmlOutput);
} else if (thestandard == EStandard.orderx) {
//zf2 or fx
applyCIO2XSLT(fis, iaos);
doPostProcessing = true;
applyCIO2XSLT(xmlContentStream, htmlOutput);
} else {
throw new IllegalArgumentException("File does not look like CII or UBL");
}
if (doPostProcessing) {
// take the copy of the stream and re-write it to an InputStream
PipedInputStream in = new PipedInputStream();
PipedOutputStream out;
try {
out = new PipedOutputStream(in);
new Thread(new Runnable() {
public void run() {
try {
// write the original OutputStream to the PipedOutputStream
// note that in order for the below method to work, you need
// to ensure that the data has finished writing to the
// ByteArrayOutputStream
iaos.writeTo(out);
} catch (IOException e) {
LOGGER.error("Failed to write to stream", e);
} finally {
// close the PipedOutputStream here because we're done writing data
// once this thread has completed its run
StreamHelper.close(out);
}
}
}).start();
applyXSLTToHTML(in, baos);
} catch (IOException e1) {
LOGGER.error("Failed to create HTML", e1);
}
Optional<InputStream> in = copyStream(htmlOutput);
ByteArrayOutputStream htmlOutStream = new ByteArrayOutputStream();
if (in.isPresent()) {
applyXSLTToHTML(in.get(), htmlOutStream);
}
return baos.toString(StandardCharsets.UTF_8);
return htmlOutStream.toString(StandardCharsets.UTF_8);
}
/**
* TODO: jstaerk: why not copy with that simple call: new ByteArrayInputStream(byteArrayOutputStream.toByteArray()) ?
*/
private Optional<InputStream> copyStream(ByteArrayOutputStream byteArrayOutputStream) {
// take the copy of the stream and re-write it to an InputStream
PipedInputStream in = new PipedInputStream();
try {
PipedOutputStream out = new PipedOutputStream(in);
new Thread(() -> {
try {
// write the original OutputStream to the PipedOutputStream
// note that in order for the below method to work, you need
// to ensure that the data has finished writing to the
// ByteArrayOutputStream
byteArrayOutputStream.writeTo(out);
} catch (IOException e) {
LOGGER.error("Failed to write to stream", e);
} finally {
// close the PipedOutputStream here because we're done writing data
// once this thread has completed its run
StreamHelper.close(out);
}
}).start();
} catch (IOException e1) {
LOGGER.error("Failed to create HTML", e1);
return Optional.empty();
}
return Optional.of(in);
}
private void initTemplates(Language lang) throws TransformerConfigurationException {
if (mXsltXRTemplate == null) {
mXsltXRTemplate = mFactory.newTemplates(
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
}
if (mXsltHTMLTemplate == null) {
mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource(
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html." + lang.name().toLowerCase() + ".xsl")));
}
if (mXsltZF1HTMLTemplate == null) {
mXsltZF1HTMLTemplate = mFactory.newTemplates(new StreamSource(
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt")));
}
}
protected String toFOP(String xmlFilename)
throws FileNotFoundException, TransformerException {
throws IOException, TransformerException {
FileInputStream fis = new FileInputStream(xmlFilename);
EStandard theStandard = findOutStandardFromRootNode(fis);
fis = new FileInputStream(xmlFilename);//rewind :-(
return toFOP(fis, theStandard);
}
protected String toFOP(InputStream is, EStandard theStandard)
throws TransformerException, IOException {
try {
if (mXsltPDFTemplate == null) {
mXsltPDFTemplate = mFactory.newTemplates(
@@ -259,45 +230,22 @@ public class ZUGFeRDVisualizer {
}
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//zf2 or fx
if (theStandard == EStandard.facturx) {
applyZF2XSLT(fis, iaos);
applyZF2XSLT(is, iaos);
} else if (theStandard == EStandard.ubl) {
applyUBL2XSLT(fis, iaos);
applyUBL2XSLT(is, iaos);
} else if (theStandard == EStandard.ubl_creditnote) {
applyUBLCreditNote2XSLT(fis, iaos);
applyUBLCreditNote2XSLT(is, iaos);
}
PipedInputStream in = new PipedInputStream();
PipedOutputStream out;
try {
out = new PipedOutputStream(in);
new Thread(new Runnable() {
public void run() {
try {
// write the original OutputStream to the PipedOutputStream
// note that in order for the below method to work, you need
// to ensure that the data has finished writing to the
// ByteArrayOutputStream
iaos.writeTo(out);
} catch (IOException e) {
LOGGER.error("Failed to write to stream", e);
} finally {
// close the PipedOutputStream here because we're done writing data
// once this thread has completed its run
StreamHelper.close(out);
}
}
}).start();
applyXSLTToPDF(in, baos);
} catch (IOException e1) {
LOGGER.error("Failed to create PDF", e1);
Optional<InputStream> in = copyStream(iaos);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (in.isPresent()) {
applyXSLTToPDF(in.get(), baos);
}
return baos.toString(StandardCharsets.UTF_8);
}
@@ -313,7 +261,7 @@ public class ZUGFeRDVisualizer {
*/
try {
result = this.toFOP(XMLinputFile.getAbsolutePath());
} catch (FileNotFoundException | TransformerException e) {
} catch (TransformerException | IOException e) {
LOGGER.error("Failed to apply FOP", e);
}
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
@@ -367,7 +315,7 @@ public class ZUGFeRDVisualizer {
}
}
protected void applyZF2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
protected void applyZF2XSLT(final InputStream xmlFile, final OutputStream htmlOutStream)
throws TransformerException {
if (mXsltXRTemplate == null) {
mXsltXRTemplate = mFactory.newTemplates(
@@ -376,10 +324,10 @@ public class ZUGFeRDVisualizer {
}
Transformer transformer = mXsltXRTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutStream));
}
protected void applyCIO2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
protected void applyCIO2XSLT(final InputStream xmlFile, final OutputStream htmlOutstream)
throws TransformerException {
if (mXsltCIOTemplate == null) {
mXsltCIOTemplate = mFactory.newTemplates(
@@ -387,10 +335,10 @@ public class ZUGFeRDVisualizer {
}
Transformer transformer = mXsltCIOTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutstream));
}
protected void applyUBL2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
protected void applyUBL2XSLT(final InputStream xmlFile, final OutputStream htmlOutStream)
throws TransformerException {
if (mXsltUBLTemplate == null) {
mXsltUBLTemplate = mFactory.newTemplates(
@@ -398,10 +346,10 @@ public class ZUGFeRDVisualizer {
}
Transformer transformer = mXsltUBLTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutStream));
}
protected void applyUBLCreditNote2XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
protected void applyUBLCreditNote2XSLT(final InputStream xmlFile, final OutputStream htmlOutStream)
throws TransformerException {
if (mXsltUBLTemplate == null) {
mXsltUBLTemplate = mFactory.newTemplates(
@@ -409,28 +357,30 @@ public class ZUGFeRDVisualizer {
}
Transformer transformer = mXsltUBLTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutStream));
}
protected void applyZF1XSLT(final InputStream xmlFile, final OutputStream HTMLOutstream)
protected void applyZF1XSLT(final InputStream xmlFile, final OutputStream htmlOutStream)
throws TransformerException {
Transformer transformer = mXsltZF1HTMLTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutStream));
}
protected void applyXSLTToHTML(final InputStream xmlFile, final OutputStream HTMLOutstream)
throws TransformerException {
protected void applyXSLTToHTML(final InputStream xmlFile, final OutputStream htmlOutStream)
throws TransformerException, IOException {
Transformer transformer = mXsltHTMLTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
transformer.transform(new StreamSource(xmlFile), new StreamResult(htmlOutStream));
xmlFile.close();
}
protected void applyXSLTToPDF(final InputStream xmlFile, final OutputStream PDFOutstream)
throws TransformerException {
throws TransformerException, IOException {
Transformer transformer = mXsltPDFTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(PDFOutstream));
xmlFile.close();
}
private static class ClasspathResourceURIResolver implements URIResolver {
@@ -439,7 +389,7 @@ public class ZUGFeRDVisualizer {
}
@Override
public Source resolve(String href, String base) throws TransformerException {
public Source resolve(String href, String base) {
return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/" + href));
}
}

View File

@@ -29,6 +29,7 @@ public class TaxCategoryCodeTypeConstants {
public static final String ZEROTAXPRODUCTS = "Z";
public static final String UNTAXEDSERVICE = "O";
public static final String INTRACOMMUNITY = "K";
public static Set<String> CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT).collect(Collectors.toSet());
public static final String FREEEXPORT = "G";
public static Set<String> CATEGORY_CODES_WITH_EXEMPTION_REASON = Stream.of(INTRACOMMUNITY, REVERSECHARGE, TAXEXEMPT, FREEEXPORT).collect(Collectors.toSet());
}

View File

@@ -106,7 +106,14 @@ public class NodeMap {
* @return the text content of the matching node, converted to BigDecimal
*/
public Optional<BigDecimal> getAsBigDecimal(String... localNames) {
return getNode(localNames).map(Node::getTextContent).map(s->new BigDecimal(s.trim()));
return getNode(localNames).map(Node::getTextContent).map(s->{
try {
return new BigDecimal(s.trim());
} catch (NumberFormatException e) {
return null;
}
});
}
/**

Binary file not shown.

Binary file not shown.

View File

@@ -1,37 +1,57 @@
<fop version="1.0">
<!-- Strict user configuration -->
<strict-configuration>true</strict-configuration>
<!-- Strict FO validation -->
<strict-validation>true</strict-validation>
<!-- Base URL for resolving relative URLs -->
<!-- Font Base URL for resolving relative font URLs -->
<!-- Source resolution in dpi (dots/pixels per inch) for determining the size of pixels in SVG and bitmap images, default: 72dpi -->
<source-resolution>96</source-resolution>
<!-- Target resolution in dpi (dots/pixels per inch) for specifying the target resolution for generated bitmaps, default: 72dpi -->
<target-resolution>96</target-resolution>
<!-- default page-height and page-width, in case
value is specified as auto -->
<default-page-settings height="297mm" width="210mm"/><!-- DIN A/4 -->
<!-- etc. etc..... -->
<renderers>
<renderer mime="application/pdf">
<fonts><!-- https://xmlgraphics.apache.org/fop/1.1/fonts.html auto-embed -->
<auto-detect/>
<font kerning="no" embed-url="classpath:FreeSans.ttf" embedding-mode="subset">
<font-triplet name="SourceSerifPro" style="normal" weight="normal" />
<font-triplet name="Times-Bold" style="normal" weight="normal" />
</font>
</fonts>
<output-profile>classpath:AdobeCompat-v2.icc</output-profile>
</renderer>
</renderers>
</fop>
<fop version="1.0">
<!-- Strict user configuration -->
<strict-configuration>true</strict-configuration>
<!-- Strict FO validation -->
<strict-validation>true</strict-validation>
<!-- Base URL for resolving relative URLs -->
<!-- Font Base URL for resolving relative font URLs -->
<!-- Source resolution in dpi (dots/pixels per inch) for determining the size of pixels in SVG and bitmap images, default: 72dpi -->
<source-resolution>96</source-resolution>
<!-- Target resolution in dpi (dots/pixels per inch) for specifying the target resolution for generated bitmaps, default: 72dpi -->
<target-resolution>96</target-resolution>
<!-- default page-height and page-width, in case
value is specified as auto -->
<default-page-settings height="297mm" width="210mm"/><!-- DIN A/4 -->
<!-- etc. etc..... -->
<renderers>
<renderer mime="application/pdf">
<fonts>
<!-- https://xmlgraphics.apache.org/fop/1.1/fonts.html auto-embed -->
<auto-detect/>
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-Regular.ttf" embedding-mode="subset">
<font-triplet name="SourceSansPro" style="normal" weight="400"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-It.ttf" embedding-mode="subset">
<font-triplet name="SourceSansPro" style="italic" weight="400"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-Bold.ttf" embedding-mode="subset">
<font-triplet name="SourceSansPro" style="normal" weight="700"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSansPro-BoldIt.ttf" embedding-mode="subset">
<font-triplet name="SourceSansPro" style="italic" weight="700"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-Regular.ttf" embedding-mode="subset">
<font-triplet name="SourceSerifPro" style="normal" weight="400"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-It.ttf" embedding-mode="subset">
<font-triplet name="SourceSerifPro" style="italic" weight="400"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-Bold.ttf" embedding-mode="subset">
<font-triplet name="SourceSerifPro" style="normal" weight="700"/>
</font>
<font kerning="yes" embed-url="classpath:fonts/SourceSerifPro-BoldIt.ttf" embedding-mode="subset">
<font-triplet name="SourceSerifPro" style="italic" weight="700"/>
</font>
</fonts>
<output-profile>classpath:AdobeCompat-v2.icc</output-profile>
</renderer>
</renderers>
</fop>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,243 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:axf="http://www.antennahouse.com/names/XSL/Extensions"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:pdf="http://xmlgraphics.apache.org/fop/extensions/pdf"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<!-- Imports -->
<xsl:import href="common-xr.xsl"/>
<xsl:import href="xr-pdf/lib/konstanten.xsl"/>
<!--
FO engine used can be specified.
Specific extensions will be then enabled.
Supported values are:
axf - Antenna House XSL Formatter
fop - Apache FOP
-->
<xsl:param name="foengine"/>
<xsl:param name="axf.extensions"
select="if ($foengine eq 'axf') then true() else false()"/>
<xsl:param name="fop.extensions"
select="if ($foengine eq 'fop') then true() else false()"/>
<xsl:variable name="xml_result_color">
<xsl:if test="/validation/xml/summary/@status = 'valid'">
<xsl:text>green</xsl:text>
</xsl:if>
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
<xsl:text>red</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:variable name="pdf_result_color">
<xsl:if test="/validation/pdf/summary/@status = 'valid'">
<xsl:text>green</xsl:text>
</xsl:if>
<xsl:if test="/validation/pdf/summary/@status = 'invalid'">
<xsl:text>red</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:variable name="pdf_result_text">
<xsl:if test="/validation/xml/summary/@status = 'valid'">
<xsl:text>Das ZUGFeRD-PDF ist valide.</xsl:text>
</xsl:if>
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
<xsl:text>Das ZUGFeRD-PDF ist nicht valide.</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:variable name="result_text">
<xsl:if test="/validation/xml/summary/@status = 'valid'">
<xsl:text>Es wird empfohlen, das Dokument anzunehmen und weiterzuverarbeiten.</xsl:text>
</xsl:if>
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
<xsl:text>Es wird empfohlen, das Dokument zurückzuweisen.</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:template match="validation">
<fo:root language="{$lang}"
font-family="{$fontSans}">
<fo:layout-master-set>
<fo:simple-page-master master-name="DIN-A4"
page-height="297mm"
page-width="210mm">
<fo:region-body region-name="body"
margin="20mm 10mm 20mm 20mm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="DIN-A4">
<fo:flow flow-name="body">
<fo:block font-size="24px"
font-weight="bold">
<xsl:text>Prüfbericht</xsl:text>
</fo:block>
<xsl:call-template name="SubHeader">
<xsl:with-param name="text"
select="&#34;Angaben zum geprüften Dokument&#34;"/>
<xsl:with-param name="color"
select="&#34;black&#34;"/>
</xsl:call-template>
<fo:block>
<fo:block text-align="justify">
<fo:float float="right">
<fo:block>
<xsl:value-of select="/validation/@filename"/>
</fo:block>
</fo:float>
<xsl:text>Referenz:</xsl:text>
</fo:block>
</fo:block>
<fo:block>
<fo:block text-align="justify">
<fo:float float="right">
<fo:block>
<xsl:value-of select="/validation/@datetime"/>
</fo:block>
</fo:float>
<xsl:text>Zeitpunkt der Prüfung:</xsl:text>
</fo:block>
</fo:block>
<fo:block>
<fo:block text-align="justify">
<fo:float float="right">
<fo:block>
<xsl:value-of select="/validation/xml/info/profile"/>
</fo:block>
</fo:float>
<xsl:text>Erkannter Dokumenttyp:</xsl:text>
</fo:block>
</fo:block>
<xsl:apply-templates select="/validation/pdf"/>
<!--
<xsl:call-template name="SubHeader">
<xsl:with-param name="text"
select='"Konformitätsprüfung:"'/>
<xsl:with-param name="color"
select='"black"'/>
</xsl:call-template>
-->
<xsl:call-template name="SubHeader">
<xsl:with-param name="text"
select="concat('Bewertung: ', $result_text)"/>
<xsl:with-param name="color"
select="$xml_result_color"/>
</xsl:call-template>
<fo:block>Validierungsergebnisse im Detail:</fo:block>
<fo:table>
<fo:table-column border-style="solid"/>
<fo:table-column border-style="solid"/>
<fo:table-column border-style="solid"/>
<fo:table-column column-width="70%"
border-style="solid"/>
<fo:table-header>
<fo:table-row background-color="#E0E0E0"
font-weight="bold">
<fo:table-cell>
<fo:block>Type</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Code</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Schwere</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Text</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:choose>
<xsl:when test="/validation/xml/messages">
<xsl:apply-templates select="/validation/xml/messages"/>
</xsl:when>
<xsl:otherwise>
<fo:table-row font-size="12px"
border-style="solid">
<fo:table-cell number-columns-spanned="4">
<fo:block text-align="center">Es gibt weder Hinweise noch Fehler.</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:otherwise>
</xsl:choose>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="notice|error">
<fo:table-row font-size="12px"
border-style="solid">
<fo:table-cell number-rows-spanned="2">
<fo:block>
<xsl:value-of select="@type"/>
</fo:block>
</fo:table-cell>
<fo:table-cell number-rows-spanned="2">
<fo:block>
<xsl:call-template name="SUBID">
<xsl:with-param name="myparam"
select="substring-after(.,' [ID ')"/>
</xsl:call-template>
</fo:block>
</fo:table-cell>
<fo:table-cell number-rows-spanned="2">
<fo:block>
<xsl:choose>
<xsl:when test="name() = 'error'">
<xsl:attribute name="color">red</xsl:attribute>
<xsl:text>Fehler</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>Hinweis</xsl:text>
</xsl:otherwise>
</xsl:choose>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:if test="name() = 'error'">
<xsl:attribute name="color">red</xsl:attribute>
</xsl:if>
<xsl:value-of select="substring-before(.,' [ID')"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row font-size="10px"
border-style="solid">
<fo:table-cell>
<fo:block>
<xsl:if test="name() = 'error'">
<xsl:attribute name="color">red</xsl:attribute>
</xsl:if>
<xsl:value-of select="concat('Pfad: ', @location)"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
<xsl:template match="pdf">
<xsl:call-template name="SubHeader">
<xsl:with-param name="text"
select="concat('ZUGFeRD-PDF: ', $pdf_result_text)"/>
<xsl:with-param name="color"
select="&#34;black&#34;"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="SubHeader">
<xsl:param name="text"/>
<xsl:param name="color"/>
<fo:block color="{$color}"
background-color="#E0E0E0"
margin-bottom="10px"
padding="3px"
font-weight="bold"
margin-top="10px">
<xsl:value-of select="$text"/>
</fo:block>
</xsl:template>
<xsl:template name="SUBID">
<xsl:param name="myparam"/>
<xsl:variable name="myparam.end"
select="substring-before($myparam, ']')"/>
<xsl:value-of select="$myparam.end"/>
</xsl:template>
</xsl:stylesheet>

View File

@@ -64,7 +64,7 @@
<x:xmpmeta xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:title><xsl:value-of select="xr:Invoice_number"/></dc:title>
<dc:title><rdf:Alt><rdf:li xml:lang="x-default"><xsl:value-of select="xr:Invoice_number"/></rdf:li></rdf:Alt></dc:title>
<!--
<dc:creator></dc:creator>
<dc:description></dc:description>

View File

@@ -1,235 +1,235 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:axf="http://www.antennahouse.com/names/XSL/Extensions"
xmlns:xr="urn:ce.eu:en16931:2017:xoev-de:kosit:standard:xrechnung-1"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xrv="http://www.example.org/XRechnung-Viewer"
xmlns:xrf="https://projekte.kosit.org/xrechnung/xrechnung-visualization/functions"
version="2.0">
<!-- ==========================================================================
== Schriften
=========================================================================== -->
<xsl:variable name="fontSans">SourceSerifPro</xsl:variable>
<xsl:variable name="fontSerif">SourceSerifPro</xsl:variable>
<xsl:variable name="amount-picture" select="xrf:_('amount-format')"/>
<xsl:variable name="percentage-picture" select="xrf:_('percentage-format')"/>
<!-- ==========================================================================
== Attribute-Sets
=========================================================================== -->
<!-- Fliesstext -->
<xsl:attribute-set name="fliesstext">
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="line-height">12pt</xsl:attribute>
<xsl:attribute name="hyphenation-ladder-count">3</xsl:attribute>
<xsl:attribute name="hyphenate">true</xsl:attribute>
<xsl:attribute name="language">de</xsl:attribute>
</xsl:attribute-set>
<!-- H1 Marker -->
<xsl:attribute-set name="marker">
<xsl:attribute name="font-size">18pt</xsl:attribute>
<xsl:attribute name="font-family"><xsl:value-of select="$fontSerif"/></xsl:attribute>
<xsl:attribute name="hyphenate">false</xsl:attribute>
<xsl:attribute name="span">all</xsl:attribute>
</xsl:attribute-set>
<!-- H1 -->
<xsl:attribute-set name="h1">
<xsl:attribute name="font-size">18pt</xsl:attribute>
<xsl:attribute name="font-family"><xsl:value-of select="$fontSerif"/></xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="margin-bottom">4mm</xsl:attribute>
<xsl:attribute name="hyphenate">false</xsl:attribute>
<xsl:attribute name="span">all</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<!-- H2-Container -->
<xsl:attribute-set name="h2-container">
<xsl:attribute name="border-top">0.5pt solid</xsl:attribute>
<xsl:attribute name="padding-top">2.5pt</xsl:attribute>
<xsl:attribute name="span">all</xsl:attribute>
<xsl:attribute name="margin-bottom">4mm</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<!-- H2 -->
<xsl:attribute-set name="h2">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="border">0.5pt solid</xsl:attribute>
<xsl:attribute name="padding">4pt 6pt</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
<xsl:attribute name="margin">0</xsl:attribute>
</xsl:attribute-set>
<!-- H3 -->
<xsl:attribute-set name="h3">
<xsl:attribute name="font-size">10pt</xsl:attribute>
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="margin-bottom">1mm</xsl:attribute>
<xsl:attribute name="margin-left">2mm</xsl:attribute>
<xsl:attribute name="margin-top">2mm</xsl:attribute>
<xsl:attribute name="span">all</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<!-- Separator -->
<xsl:attribute-set name="separator">
<xsl:attribute name="margin-left">2mm</xsl:attribute>
<xsl:attribute name="margin-bottom">3mm</xsl:attribute>
<xsl:attribute name="border-bottom">0.5pt dotted</xsl:attribute>
<xsl:attribute name="color">#999999</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<!-- Wert-Felder -->
<xsl:variable name="wertHG">#eeeeee</xsl:variable>
<xsl:variable name="wert-legende-breite">28</xsl:variable>
<xsl:attribute-set name="wert-legende">
<xsl:attribute name="font-size">7pt</xsl:attribute>
<xsl:attribute name="line-height">10pt</xsl:attribute>
<xsl:attribute name="padding-top">1mm</xsl:attribute>
<xsl:attribute name="padding-bottom">1mm</xsl:attribute>
<xsl:attribute name="margin-left">2mm</xsl:attribute>
<xsl:attribute name="padding-right">1mm</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="wert-ausgabe">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="line-height">10pt</xsl:attribute>
<xsl:attribute name="background-color"><xsl:value-of select="$wertHG"/></xsl:attribute>
<xsl:attribute name="padding-top">1mm</xsl:attribute>
<xsl:attribute name="padding-bottom">1mm</xsl:attribute>
<xsl:attribute name="padding-left">2mm</xsl:attribute>
<xsl:attribute name="padding-right">2mm</xsl:attribute>
<xsl:attribute name="keep-together.within-column">always</xsl:attribute>
</xsl:attribute-set>
<!-- Rechnung-Felder -->
<xsl:attribute-set name="rechnung-legende">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="text-align">left</xsl:attribute>
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">1mm</xsl:attribute>
<xsl:attribute name="margin-left">0mm</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="rechnung-steuer">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="text-align">left</xsl:attribute>
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">1mm</xsl:attribute>
<xsl:attribute name="margin-left">0mm</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="rechnung-wert">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="text-align">right</xsl:attribute>
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">0mm</xsl:attribute>
<xsl:attribute name="margin-left">0mm</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="rechnung-legende-summe">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="text-align">left</xsl:attribute>
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">1mm</xsl:attribute>
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="rechnung-steuer-summe">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="text-align">left</xsl:attribute>
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">1mm</xsl:attribute>
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="rechnung-wert-summe">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="text-align">right</xsl:attribute>
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">0mm</xsl:attribute>
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<!-- Box-Container -->
<xsl:attribute-set name="box-container-kapitel">
<xsl:attribute name="margin-bottom">10mm</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="box-container-bereich">
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
<xsl:attribute name="keep-together.within-page">always</xsl:attribute>
<xsl:attribute name="span">all</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="box-container-inner">
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
</xsl:attribute-set>
<!-- Tabular invoice lines -->
<xsl:attribute-set name="invoicelines-table">
<xsl:attribute name="padding-left">2pt</xsl:attribute>
<xsl:attribute name="padding-right">2pt</xsl:attribute>
<xsl:attribute name="width">100%</xsl:attribute>
<xsl:attribute name="table-layout">fixed</xsl:attribute>
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="invoicelines-table-header">
<xsl:attribute name="font-weight">bold</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="invoicelines-table-row">
<!-- Nested sub-invoice lines will recursively decrease font-size -->
<xsl:attribute name="font-size" select="if (self::xr:SUB_INVOICE_LINE) then '90%' else '100%'"/>
</xsl:attribute-set>
<xsl:attribute-set name="invoicelines-nested-info">
<xsl:attribute name="font-size">80%</xsl:attribute>
<xsl:attribute name="font-style">italic</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="invoicelines-allowances-table">
<xsl:attribute name="padding-left">2pt</xsl:attribute>
<xsl:attribute name="padding-right">2pt</xsl:attribute>
<xsl:attribute name="width">100%</xsl:attribute>
<xsl:attribute name="table-layout">fixed</xsl:attribute>
<xsl:attribute name="font-size">80%</xsl:attribute>
<xsl:attribute name="font-style">italic</xsl:attribute>
</xsl:attribute-set>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:axf="http://www.antennahouse.com/names/XSL/Extensions"
xmlns:xr="urn:ce.eu:en16931:2017:xoev-de:kosit:standard:xrechnung-1"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xrv="http://www.example.org/XRechnung-Viewer"
xmlns:xrf="https://projekte.kosit.org/xrechnung/xrechnung-visualization/functions"
version="2.0">
<!-- ==========================================================================
== Schriften
=========================================================================== -->
<xsl:variable name="fontSans">SourceSansPro</xsl:variable>
<xsl:variable name="fontSerif">SourceSerifPro</xsl:variable>
<xsl:variable name="amount-picture" select="xrf:_('amount-format')"/>
<xsl:variable name="percentage-picture" select="xrf:_('percentage-format')"/>
<!-- ==========================================================================
== Attribute-Sets
=========================================================================== -->
<!-- Fliesstext -->
<xsl:attribute-set name="fliesstext">
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="line-height">12pt</xsl:attribute>
<xsl:attribute name="hyphenation-ladder-count">3</xsl:attribute>
<xsl:attribute name="hyphenate">true</xsl:attribute>
<xsl:attribute name="language">de</xsl:attribute>
</xsl:attribute-set>
<!-- H1 Marker -->
<xsl:attribute-set name="marker">
<xsl:attribute name="font-size">18pt</xsl:attribute>
<xsl:attribute name="font-family"><xsl:value-of select="$fontSerif"/></xsl:attribute>
<xsl:attribute name="hyphenate">false</xsl:attribute>
<xsl:attribute name="span">all</xsl:attribute>
</xsl:attribute-set>
<!-- H1 -->
<xsl:attribute-set name="h1">
<xsl:attribute name="font-size">18pt</xsl:attribute>
<xsl:attribute name="font-family"><xsl:value-of select="$fontSerif"/></xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="margin-bottom">4mm</xsl:attribute>
<xsl:attribute name="hyphenate">false</xsl:attribute>
<xsl:attribute name="span">all</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<!-- H2-Container -->
<xsl:attribute-set name="h2-container">
<xsl:attribute name="border-top">0.5pt solid</xsl:attribute>
<xsl:attribute name="padding-top">2.5pt</xsl:attribute>
<xsl:attribute name="span">all</xsl:attribute>
<xsl:attribute name="margin-bottom">4mm</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<!-- H2 -->
<xsl:attribute-set name="h2">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="border">0.5pt solid</xsl:attribute>
<xsl:attribute name="padding">4pt 6pt</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
<xsl:attribute name="margin">0</xsl:attribute>
</xsl:attribute-set>
<!-- H3 -->
<xsl:attribute-set name="h3">
<xsl:attribute name="font-size">10pt</xsl:attribute>
<xsl:attribute name="font-family"><xsl:value-of select="$fontSans"/></xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="margin-bottom">1mm</xsl:attribute>
<xsl:attribute name="margin-left">2mm</xsl:attribute>
<xsl:attribute name="margin-top">2mm</xsl:attribute>
<xsl:attribute name="span">all</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<!-- Separator -->
<xsl:attribute-set name="separator">
<xsl:attribute name="margin-left">2mm</xsl:attribute>
<xsl:attribute name="margin-bottom">3mm</xsl:attribute>
<xsl:attribute name="border-bottom">0.5pt dotted</xsl:attribute>
<xsl:attribute name="color">#999999</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<!-- Wert-Felder -->
<xsl:variable name="wertHG">#eeeeee</xsl:variable>
<xsl:variable name="wert-legende-breite">28</xsl:variable>
<xsl:attribute-set name="wert-legende">
<xsl:attribute name="font-size">7pt</xsl:attribute>
<xsl:attribute name="line-height">10pt</xsl:attribute>
<xsl:attribute name="padding-top">1mm</xsl:attribute>
<xsl:attribute name="padding-bottom">1mm</xsl:attribute>
<xsl:attribute name="margin-left">2mm</xsl:attribute>
<xsl:attribute name="padding-right">1mm</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="wert-ausgabe">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="line-height">10pt</xsl:attribute>
<xsl:attribute name="background-color"><xsl:value-of select="$wertHG"/></xsl:attribute>
<xsl:attribute name="padding-top">1mm</xsl:attribute>
<xsl:attribute name="padding-bottom">1mm</xsl:attribute>
<xsl:attribute name="padding-left">2mm</xsl:attribute>
<xsl:attribute name="padding-right">2mm</xsl:attribute>
<xsl:attribute name="keep-together.within-column">always</xsl:attribute>
</xsl:attribute-set>
<!-- Rechnung-Felder -->
<xsl:attribute-set name="rechnung-legende">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="text-align">left</xsl:attribute>
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">1mm</xsl:attribute>
<xsl:attribute name="margin-left">0mm</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="rechnung-steuer">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="text-align">left</xsl:attribute>
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">1mm</xsl:attribute>
<xsl:attribute name="margin-left">0mm</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="rechnung-wert">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="text-align">right</xsl:attribute>
<xsl:attribute name="padding-top">0.2mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">0mm</xsl:attribute>
<xsl:attribute name="margin-left">0mm</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="rechnung-legende-summe">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="text-align">left</xsl:attribute>
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">1mm</xsl:attribute>
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="rechnung-steuer-summe">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="text-align">left</xsl:attribute>
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">1mm</xsl:attribute>
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="rechnung-wert-summe">
<xsl:attribute name="font-size">9pt</xsl:attribute>
<xsl:attribute name="font-weight">bold</xsl:attribute>
<xsl:attribute name="text-align">right</xsl:attribute>
<xsl:attribute name="padding-top">0.4mm</xsl:attribute>
<xsl:attribute name="padding-bottom">0.2mm</xsl:attribute>
<xsl:attribute name="padding-left">0mm</xsl:attribute>
<xsl:attribute name="padding-right">0mm</xsl:attribute>
<xsl:attribute name="border-top">0.1pt solid #999999</xsl:attribute>
<xsl:attribute name="keep-with-next.within-page">always</xsl:attribute>
</xsl:attribute-set>
<!-- Box-Container -->
<xsl:attribute-set name="box-container-kapitel">
<xsl:attribute name="margin-bottom">10mm</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="box-container-bereich">
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
<xsl:attribute name="keep-together.within-page">always</xsl:attribute>
<xsl:attribute name="span">all</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="box-container-inner">
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
</xsl:attribute-set>
<!-- Tabular invoice lines -->
<xsl:attribute-set name="invoicelines-table">
<xsl:attribute name="padding-left">2pt</xsl:attribute>
<xsl:attribute name="padding-right">2pt</xsl:attribute>
<xsl:attribute name="width">100%</xsl:attribute>
<xsl:attribute name="table-layout">fixed</xsl:attribute>
<xsl:attribute name="margin-bottom">2mm</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="invoicelines-table-header">
<xsl:attribute name="font-weight">bold</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="invoicelines-table-row">
<!-- Nested sub-invoice lines will recursively decrease font-size -->
<xsl:attribute name="font-size" select="if (self::xr:SUB_INVOICE_LINE) then '90%' else '100%'"/>
</xsl:attribute-set>
<xsl:attribute-set name="invoicelines-nested-info">
<xsl:attribute name="font-size">80%</xsl:attribute>
<xsl:attribute name="font-style">italic</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="invoicelines-allowances-table">
<xsl:attribute name="padding-left">2pt</xsl:attribute>
<xsl:attribute name="padding-right">2pt</xsl:attribute>
<xsl:attribute name="width">100%</xsl:attribute>
<xsl:attribute name="table-layout">fixed</xsl:attribute>
<xsl:attribute name="font-size">80%</xsl:attribute>
<xsl:attribute name="font-style">italic</xsl:attribute>
</xsl:attribute-set>
</xsl:stylesheet>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -21,18 +21,29 @@
*/
package org.mustangproject.ZUGFeRD;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import junit.framework.TestCase;
import org.junit.Assert;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import org.mustangproject.*;
import org.mustangproject.ZUGFeRD.model.EventTimeCodeTypeConstants;
import javax.xml.xpath.XPathExpressionException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class DeSerializationTest extends TestCase {
public class DeSerializationTest extends ResourceCase {
public void testJackson() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
@@ -49,4 +60,736 @@ public class DeSerializationTest extends TestCase {
assertEquals("info@company.com", fromJSON.getSender().getUriUniversalCommunicationID());
}
public void testInvoiceLine() throws JsonProcessingException {
File inputCII = getResourceAsFile("factur-x.xml");
boolean hasExceptions = false;
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
try {
zii.fromXML(new String(Files.readAllBytes(inputCII.toPath()), StandardCharsets.UTF_8));
} catch (IOException e) {
hasExceptions = true;
}
CalculatedInvoice ci = new CalculatedInvoice();
try {
zii.extractInto(ci);
} catch (XPathExpressionException e) {
hasExceptions = true;
} catch (ParseException e) {
hasExceptions = true;
}
ObjectMapper mapper = new ObjectMapper();
String jsonArray = mapper.writeValueAsString(ci);
assertFalse(hasExceptions);
assertTrue(jsonArray.contains("lineTotalAmount"));
}
public void testAllowanceRead() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
// [{"stringValue":"a","intValue":1,"booleanValue":true},
// {"stringValue":"bc","intValue":3,"booleanValue":false}]
Invoice fromJSON = mapper.readValue("{\n" +
" \"documentCode\": \"380\",\n" +
" \"number\": \"471102\",\n" +
" \"ownOrganisationName\": \"Lieferant GmbH\",\n" +
" \"currency\": \"EUR\",\n" +
" \"issueDate\": \"2018-03-03T23:00:00.000+00:00\",\n" +
" \"deliveryDate\": \"2018-03-03T23:00:00.000+00:00\",\n" +
" \"sender\": {\n" +
" \"name\": \"Lieferant GmbH\",\n" +
" \"zip\": \"80333\",\n" +
" \"street\": \"Lieferantenstraße 20\",\n" +
" \"location\": \"München\",\n" +
" \"country\": \"DE\",\n" +
" \"taxID\": \"201/113/40209\",\n" +
" \"vatID\": \"DE123456789\",\n" +
" \"vatid\": \"DE123456789\"\n" +
" },\n" +
" \"recipient\": {\n" +
" \"name\": \"Kunden AG Mitte\",\n" +
" \"zip\": \"69876\",\n" +
" \"street\": \"Kundenstraße 15\",\n" +
" \"location\": \"Frankfurt\",\n" +
" \"country\": \"DE\"\n" +
" },\n" +
" \"grandTotal\": 234.43,\n" +
" \"zfitems\": [\n" +
" {\n" +
" \"price\": 9.9,\n" +
" \"quantity\": 20,\n" +
" \"tax\": null,\n" +
" \"grossPrice\": null,\n" +
" \"lineTotalAmount\": null,\n" +
" \"basisQuantity\": 1,\n" +
" \"detailedDeliveryPeriodFrom\": null,\n" +
" \"detailedDeliveryPeriodTo\": null,\n" +
" \"id\": null,\n" +
" \"product\": {\n" +
" \"unit\": \"H87\",\n" +
" \"name\": \"Trennblätter A4\",\n" +
" \"taxCategoryCode\": \"S\",\n" +
" \"attributes\": null,\n" +
" \"vatpercent\": 19\n" +
" },\n" +
" \"value\": 9.9\n" +
" }\n" +
" ],\n" +
" \"tradeSettlement\": null,\n" +
" \"ownTaxID\": \"201/113/40209\",\n" +
" \"ownVATID\": \"DE123456789\",\n" +
" \"ownStreet\": \"Lieferantenstraße 20\",\n" +
" \"ownZIP\": \"80333\",\n" +
" \"ownLocation\": \"München\",\n" +
" \"ownCountry\": \"DE\",\n" +
" \"zfallowances\": [\n" +
" {\n" +
" \"totalAmount\": 1,\n" +
" \"taxPercent\": 19,\n" +
" \"reason\": \"Sondernachlass\",\n" +
" \"reasonCode\": null,\n" +
" \"categoryCode\": \"S\",\n" +
" \"charge\": false\n" +
" }\n" +
" ]\n" +
"}", Invoice.class);
TransactionCalculator tc = new TransactionCalculator(fromJSON);
assertEquals(tc.getGrandTotal(), new BigDecimal("234.43"));
assertEquals(fromJSON.getNumber(), fromJSON.getNumber());
assertEquals(fromJSON.getZFItems().length, fromJSON.getZFItems().length);
}
public void testDeserializedFiles() {
File inputUBL = getResourceAsFile("XRECHNUNG_Elektron.ubl.xml");
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
zii.doIgnoreCalculationErrors();
Invoice i = new Invoice();
String exText = null;
try {
zii.fromXML(new String(Files.readAllBytes(inputUBL.toPath()), StandardCharsets.UTF_8));
ObjectMapper mapper = new ObjectMapper();
zii.extractInto(i);
String json = mapper.writeValueAsString(i);
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
assertEquals("181301674", i.getNumber());
assertEquals(newInvoiceFromJSON.getNumber(), i.getNumber());
assertEquals(newInvoiceFromJSON.getAdditionalReferencedDocuments()[0].getFilename(), i.getAdditionalReferencedDocuments()[0].getFilename());
assertEquals(newInvoiceFromJSON.getAdditionalReferencedDocuments().length, 2);
} catch (IOException e) {
exText = e.getMessage();
} catch (XPathExpressionException e) {
exText = e.getMessage();
} catch (ParseException e) {
exText = e.getMessage();
}
assertNull(exText);
}
public void testFileSerialization() {
String base64 = "b25ldHdvdGhyZWU=";
String json = "{\n" +
" \"additionalReferencedDocuments\": [\n" +
" {\n" +
" \"data\": \"" + base64 + "\",\n" +
" \"description\": \"Additional file attachment\",\n" +
" \"filename\": \"text.txt\",\n" +
" \"mimetype\": \"text/plain\",\n" +
" \"relation\": \"Data\"\n" +
" }\n" +
"],\n" +
"\n" +
" \"number\": \"471102\",\n" +
" \"currency\": \"EUR\",\n" +
" \"issueDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
" \"dueDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
" \"deliveryDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
" \"sender\": {\n" +
" \"name\": \"Lieferant GmbH\",\n" +
" \"zip\": \"80333\",\n" +
" \"street\": \"Lieferantenstraße 20\",\n" +
" \"location\": \"München\",\n" +
" \"country\": \"DE\",\n" +
" \"taxID\": \"201/113/40209\",\n" +
" \"vatID\": \"DE123456789\",\n" +
" \"globalID\": \"4000001123452\",\n" +
" \"globalIDScheme\": \"0088\"\n" +
" },\n" +
" \"recipient\": {\n" +
" \"name\": \"Kunden AG Mitte\",\n" +
" \"zip\": \"69876\",\n" +
" \"street\": \"Kundenstraße 15\",\n" +
" \"location\": \"Frankfurt\",\n" +
" \"country\": \"DE\"\n" +
" },\n" +
" \"zfitems\": [\n" +
" {\n" +
" \"price\": 9.9,\n" +
" \"quantity\": 20,\n" +
" \"product\": {\n" +
" \"unit\": \"H87\",\n" +
" \"name\": \"Trennblätter A4\",\n" +
" \"description\": \"\",\n" +
" \"vatpercent\": 19,\n" +
" \"taxCategoryCode\": \"S\"\n" +
" }\n" +
" },\n" +
" {\n" +
" \"price\": 5.5,\n" +
" \"quantity\": 50,\n" +
" \"product\": {\n" +
" \"unit\": \"H87\",\n" +
" \"name\": \"Joghurt Banane\",\n" +
" \"description\": \"\",\n" +
" \"vatpercent\": 7,\n" +
" \"taxCategoryCode\": \"S\"\n" +
" }\n" +
" }\n" +
" ]\n" +
"}\n";
ObjectMapper mapper = new ObjectMapper();
try {
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
zf2p.setProfile(Profiles.getByName("XRechnung"));
zf2p.generateXML(newInvoiceFromJSON);
String theXML = new String(zf2p.getXML());
assertTrue(theXML.contains("<udt:DateTimeString format=\"102\">20180304</udt:DateTimeString>"));
assertTrue(theXML.contains(base64));
} catch (Exception e) {
fail("No exception expected");
}
}
public void testFull300Roundtrip() {
File inputCII = getResourceAsFile("not_validating_full_invoice_based_onTest_EeISI_300_CENfullmodel.cii.xml");
Invoice i = new Invoice();
String exText = null;
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
zii.doIgnoreCalculationErrors();
try {
zii.fromXML(new String(Files.readAllBytes(inputCII.toPath()), StandardCharsets.UTF_8));
ObjectMapper mapper = new ObjectMapper();
zii.extractInto(i);
String json = mapper.writeValueAsString(i);
Invoice newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
assertEquals("Test_EeISI_100", i.getNumber());
assertEquals(newInvoiceFromJSON.getNumber(), i.getNumber());
} catch (IOException e) {
exText = e.getMessage();
} catch (XPathExpressionException e) {
exText = e.getMessage();
} catch (ParseException e) {
exText = e.getMessage();
}
assertNull(exText);
}
public void testIssuerAssignedIDRoundtrip() {
String occurrenceFrom = "20201001";
String occurrenceTo = "20201005";
String contractID = "376zreurzu0983";
String orgID = "0009845";
String orgname = "Test company";
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");
try {
SchemedID gtin = new SchemedID("0160", "2001015001325");
SchemedID gln = new SchemedID("0088", "4304171000002");
Invoice i = new Invoice().setCurrency("CHF").addNote("document level 1/2").addNote("document level 2/2").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
.setSellerOrderReferencedDocumentID("9384").setBuyerOrderReferencedDocumentID("28934")
.setDetailedDeliveryPeriod(new SimpleDateFormat("yyyyMMdd").parse(occurrenceFrom), new SimpleDateFormat("yyyyMMdd").parse(occurrenceTo))
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID(taxID).setEmail("sender@test.org").setID(orgID).addVATID("DE0815"))
.setDeliveryAddress(new TradeParty("just the other side of the street", "teststr.12a", "55232", "Entenhausen", "DE").addVATID("DE47110"))
.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", "", "H87", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).setId("a123").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))
.setDeliveryDate(sdf.parse("2020-11-02")).setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE);
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(i);
newInvoiceFromJSON = mapper.readValue(json, Invoice.class);
} catch (ParseException e) {
hasExceptions = true;
} catch (JsonProcessingException e) {
hasExceptions = true;
}
assertEquals(newInvoiceFromJSON.getBuyerOrderReferencedDocumentID(), "28934");
assertFalse(hasExceptions);
}
public void testDueDateRoundtrip() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
// [{"stringValue":"a","intValue":1,"booleanValue":true},
// {"stringValue":"bc","intValue":3,"booleanValue":false}]
Invoice fromJSON = mapper.readValue("{\n" +
" \"number\": \"RE - 228\",\n" +
" \"currency\": \"EUR\",\n" +
" \"issueDate\": \"2024-10-24\",\n" +
" \"dueDate\": \"2024-10-26\",\n" +
" \"deliveryDate\": \"2024-10-25\",\n" +
" \"sender\": {\n" +
" \"name\": \"Amazing Company\",\n" +
" \"zip\": \"10000\",\n" +
" \"street\": \"Straße der Kosmonauten 20\",\n" +
" \"location\": \"Berlin\",\n" +
" \"country\": \"DE\",\n" +
" \"taxID\": \"201/113/40209\",\n" +
" \"vatID\": \"DE123456789\",\n" +
" \"globalID\": \"4000001123452\",\n" +
" \"globalIDScheme\": \"0088\"\n" +
" },\n" +
" \"recipient\": {\n" +
" \"name\": \"Amazing Company\",\n" +
" \"zip\": \"1000\",\n" +
" \"street\": \"Straße der Kosmonauten 10\",\n" +
" \"location\": \"Berlin\",\n" +
" \"taxID\": \"201/113/40209\",\n" +
" \"vatID\": \"DE123456789\",\n" +
" \"country\": \"DE\"\n" +
" },\n" +
" \"zfitems\": [\n" +
" {\n" +
" \"price\": 99.9,\n" +
" \"quantity\": 10,\n" +
" \"product\": {\n" +
" \"unit\": \"H87\",\n" +
" \"name\": \"Amazing Archives\",\n" +
" \"description\": \"123\",\n" +
" \"vatpercent\": \"19\",\n" +
" \"taxCategoryCode\": \"3\"\n" +
" }\n" +
" }\n" +
" ]\n" +
"}\n", Invoice.class);
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
zf2p.setProfile(Profiles.getByName("XRechnung"));
zf2p.generateXML(fromJSON);
String theXML = new String(zf2p.getXML());
assertTrue(theXML.contains("<udt:DateTimeString format=\"102\">20241026</udt:DateTimeString>"));
}
public void testDirectDebit() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
// [{"stringValue":"a","intValue":1,"booleanValue":true},
// {"stringValue":"bc","intValue":3,"booleanValue":false}]
boolean exceptions = false;
String theXML = "";
try {
Invoice fromJSON = mapper.readValue("\n" +
"\t{\n" +
"\t\t\"documentCode\": \"380\",\n" +
"\t\t\"number\": \"F20220031\",\n" +
"\t\t\"referenceNumber\": \"SERVEXEC\",\n" +
"\t\t\"buyerOrderReferencedDocumentID\": \"PO201925478\",\n" +
"\t\t\"ownOrganisationName\": \"LE FOURNISSEUR\",\n" +
"\t\t\"currency\": \"EUR\",\n" +
"\t\t\"issueDate\": \"2022-01-30T23:00:00.000+00:00\",\n" +
"\t\t\"dueDate\": \"2022-03-01T23:00:00.000+00:00\",\n" +
"\t\t\"deliveryDate\": \"2022-01-27T23:00:00.000+00:00\",\n" +
"\t\t\"sender\": {\n" +
"\t\t\"name\": \"LE FOURNISSEUR\",\n" +
"\t\t\t\"zip\": \"75018\",\n" +
"\t\t\t\"street\": \"35 rue d'ici\",\n" +
"\t\t\t\"location\": \"PARIS\",\n" +
"\t\t\t\"country\": \"FR\",\n" +
"\t\t\t\"vatID\": \"FR11123456782\",\n" +
"\t\t\t\"additionalAddress\": \"Seller line 2\",\n" +
"\t\t\t\"additionalAddressExtension\": \"Seller line 3\",\n" +
"\t\t\t\"bankDetails\": [\n" +
"\t\t{\n" +
"\t\t\t\"accountName\": null,\n" +
"\t\t\t\"iban\": \"FR20 1254 2547 2569 8542 5874 698\",\n" +
"\t\t\t\"bic\": \"BIC_MONCOMPTE\"\n" +
"\t\t}\n" +
" ],\n" +
"\t\t\"debitDetails\": [\n" +
"\t\t{\n" +
"\t\t\t\"mandate\": \"MANDATE PT\",\n" +
"\t\t\t\"iban\": \"FR20 1254 2547 2569 8542 5874 698\"\n" +
"\t\t}\n" +
" ],\n" +
"\t\t\"contact\": {\n" +
"\t\t\t\"name\": \"M. CONTACT\",\n" +
"\t\t\t\t\"phone\": \"01 02 03 54 87\",\n" +
"\t\t\t\t\"email\": \"seller@seller.com\",\n" +
"\t\t\t\t\"zip\": null,\n" +
"\t\t\t\t\"street\": null,\n" +
"\t\t\t\t\"location\": null,\n" +
"\t\t\t\t\"country\": null,\n" +
"\t\t\t\t\"fax\": null,\n" +
"\t\t\t\t\"vatid\": null,\n" +
"\t\t\t\t\"id\": null,\n" +
"\t\t\t\t\"additionalAddress\": null\n" +
"\t\t},\n" +
"\t\t\"email\": \"moi@seller.com\",\n" +
"\t\t\t\"vatid\": \"FR11123456782\",\n" +
"\t\t\t\"id\": \"123\",\n" +
"\t\t\t\"legalOrganisation\": {\n" +
"\t\t\t\"schemedID\": null,\n" +
"\t\t\t\t\"tradingBusinessName\": \"SELLER TRADE NAME\"\n" +
"\t\t},\n" +
"\t\t\"globalID\": \"587451236587\",\n" +
"\t\t\t\"globalIDScheme\": \"0088\"\n" +
"\t},\n" +
"\t\t\"recipient\": {\n" +
"\t\t\"name\": \"LE CLIENT\",\n" +
"\t\t\t\"zip\": \"06000\",\n" +
"\t\t\t\"street\": \"MON ADRESSE LIGNE 1\",\n" +
"\t\t\t\"location\": \"MA VILLE\",\n" +
"\t\t\t\"country\": \"FR\",\n" +
"\t\t\t\"vatID\": \"FR 05 987 654 321\",\n" +
"\t\t\t\"additionalAddress\": \"Buyer line 2\",\n" +
"\t\t\t\"additionalAddressExtension\": \"Buyer line 3\",\n" +
"\t\t\t\"contact\": {\n" +
"\t\t\t\"name\": \"Buyer contact name\",\n" +
"\t\t\t\t\"phone\": \"01 01 25 45 87\",\n" +
"\t\t\t\t\"email\": \"buyer@buyer.com\",\n" +
"\t\t\t\t\"zip\": null,\n" +
"\t\t\t\t\"street\": null,\n" +
"\t\t\t\t\"location\": null,\n" +
"\t\t\t\t\"country\": null,\n" +
"\t\t\t\t\"fax\": null,\n" +
"\t\t\t\t\"vatid\": null,\n" +
"\t\t\t\t\"id\": null,\n" +
"\t\t\t\t\"additionalAddress\": null\n" +
"\t\t},\n" +
"\t\t\"email\": \"me@buyer.com\",\n" +
"\t\t\t\"vatid\": \"FR 05 987 654 321\",\n" +
"\t\t\t\"legalOrganisation\": {\n" +
"\t\t\t\"schemedID\": null,\n" +
"\t\t\t\t\"tradingBusinessName\": null\n" +
"\t\t},\n" +
"\t\t\"globalID\": \"3654789851\",\n" +
"\t\t\t\"globalIDScheme\": \"0088\"\n" +
"\t},\n" +
"\t\t\"deliveryAddress\": {\n" +
"\t\t\"name\": \"DEL Name\",\n" +
"\t\t\t\"zip\": \"06000\",\n" +
"\t\t\t\"street\": \"DEL ADRESSE LIGNE 1\",\n" +
"\t\t\t\"location\": \"NICE\",\n" +
"\t\t\t\"country\": \"FR\",\n" +
"\t\t\t\"additionalAddress\": \"DEL line 2\",\n" +
"\t\t\t\"id\": \"PRIVATE_ID_DEL\"\n" +
"\t},\n" +
"\t\t\"payee\": {\n" +
"\t\t\"name\": \"PAYEE NAME\",\n" +
"\t\t\t\"legalOrganisation\": {\n" +
"\t\t\t\"schemedID\": null,\n" +
"\t\t\t\t\"tradingBusinessName\": null\n" +
"\t\t},\n" +
"\t\t\"globalID\": \"587451236586\",\n" +
"\t\t\t\"globalIDScheme\": \"0088\"\n" +
"\t},\n" +
"\t\t\"sellerOrderReferencedDocumentID\": \"SALES REF 2547\",\n" +
"\t\t\"despatchAdviceReferencedDocumentID\": \"DESPADV002\",\n" +
"\t\t\"grandTotal\": 107.82,\n" +
"\t\t\"detailedDeliveryPeriodFrom\": \"2021-12-31T23:00:00.000+00:00\",\n" +
"\t\t\"detailedDeliveryPeriodTo\": \"2022-12-30T23:00:00.000+00:00\",\n" +
"\t\t\"notesWithSubjectCode\": [\n" +
"\t\t{\n" +
"\t\t\t\"content\": \"FOURNISSEUR F SARL au capital de 50 000 EUR\",\n" +
"\t\t\t\"subjectCode\": \"REG\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"content\": \"RCS MAVILLE 123 456 782\",\n" +
"\t\t\t\"subjectCode\": \"ABL\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"content\": \"35 ma rue a moi, code postal Ville Pays contact@masociete.fr - www.masociete.fr N° TVA : FR32 123 456 789\",\n" +
"\t\t\t\"subjectCode\": \"AAI\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"content\": \"Tout retard de paiement engendre une pénalité exigible à compter de la date d'échéance, calculée sur la base de trois fois le taux d'intérêt légal.\",\n" +
"\t\t\t\"subjectCode\": null\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"content\": \"Indemnité forfaitaire pour frais de recouvrement en cas de retard de paiement : 40 €.\",\n" +
"\t\t\t\"subjectCode\": null\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"content\": \"Les réglements reçus avant la date d'échéance ne donneront pas lieu à escompte.\",\n" +
"\t\t\t\"subjectCode\": null\n" +
"\t\t}\n" +
" ],\n" +
"\t\t\"zfallowances\": [\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
"\t\t\t\"reasonCode\": \"71\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
"\t\t\t\"reasonCode\": \"71\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
"\t\t\t\"reasonCode\": \"71\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": null,\n" +
"\t\t\t\"reasonCode\": \"100\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 2,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
"\t\t\t\"reasonCode\": \"71\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
"\t\t\t\"reasonCode\": \"71\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"REMISE VOLUME\",\n" +
"\t\t\t\"reasonCode\": \"71\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": null,\n" +
"\t\t\t\"reasonCode\": \"100\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1.4,\n" +
"\t\t\t\"taxPercent\": 20,\n" +
"\t\t\t\"reason\": \"REMISE COMMERCIALE\",\n" +
"\t\t\t\"reasonCode\": \"100\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1.2,\n" +
"\t\t\t\"taxPercent\": 10,\n" +
"\t\t\t\"reason\": \"REMISE COMMERCIALE\",\n" +
"\t\t\t\"reasonCode\": \"100\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t}\n" +
" ],\n" +
"\t\t\"zfcharges\": [\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
"\t\t\t\"reasonCode\": null,\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
"\t\t\t\"reasonCode\": null,\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
"\t\t\t\"reasonCode\": null,\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
"\t\t\t\"reasonCode\": null,\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": null,\n" +
"\t\t\t\"reasonCode\": \"ADL\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
"\t\t\t\"reasonCode\": null,\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 1,\n" +
"\t\t\t\"taxPercent\": null,\n" +
"\t\t\t\"reason\": \"FRAIS PALETTE\",\n" +
"\t\t\t\"reasonCode\": null,\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 2.8,\n" +
"\t\t\t\"taxPercent\": 20,\n" +
"\t\t\t\"reason\": \"FRAIS DEPLACEMENT\",\n" +
"\t\t\t\"reasonCode\": \"FC\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"percent\": null,\n" +
"\t\t\t\"totalAmount\": 0.6,\n" +
"\t\t\t\"taxPercent\": 10,\n" +
"\t\t\t\"reason\": \"FRAIS DEPLACEMENT\",\n" +
"\t\t\t\"reasonCode\": \"ADR\",\n" +
"\t\t\t\"categoryCode\": \"S\"\n" +
"\t\t}\n" +
" ],\n" +
"\t\t\"tradeSettlement\": [\n" +
"\t\t{\n" +
"\t\t\t\"accountName\": null,\n" +
"\t\t\t\"iban\": \"FR20 1254 2547 2569 8542 5874 698\",\n" +
"\t\t\t\"bic\": \"BIC_MONCOMPTE\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"mandate\": \"MANDATE PT\",\n" +
"\t\t\t\"iban\": \"FR20 1254 2547 2569 8542 5874 698\"\n" +
"\t\t}\n" +
" ],\n" +
"\t\t\"zfitems\": [\n" +
"\t\t{\n" +
"\t\t\t\"price\": 60,\n" +
"\t\t\t\"quantity\": 1,\n" +
"\t\t\t\"basisQuantity\": 1,\n" +
"\t\t\t\"product\": {\n" +
"\t\t\t\"unit\": \"C62\",\n" +
"\t\t\t\t\"name\": \"REMBOURSEMENT AFFRANCHISSEMENT\",\n" +
"\t\t\t\t\"description\": \"Description\",\n" +
"\t\t\t\t\"taxCategoryCode\": \"Z\",\n" +
"\t\t\t\t\"vatpercent\": 0,\n" +
"\t\t\t\t\"reverseCharge\": false,\n" +
"\t\t\t\t\"intraCommunitySupply\": false,\n" +
"\t\t\t\t\"globalID\": \"598785412598745\",\n" +
"\t\t\t\t\"globalIDScheme\": \"0160\"\n" +
"\t\t},\n" +
"\t\t\t\"buyerOrderReferencedDocumentLineID\": \"1\",\n" +
"\t\t\t\"value\": 60\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"price\": 30,\n" +
"\t\t\t\"quantity\": 3,\n" +
"\t\t\t\"basisQuantity\": 3,\n" +
"\t\t\t\"product\": {\n" +
"\t\t\t\"unit\": \"C62\",\n" +
"\t\t\t\t\"name\": \"FOURNITURES DIVERSES\",\n" +
"\t\t\t\t\"description\": \"Description\",\n" +
"\t\t\t\t\"taxCategoryCode\": \"S\",\n" +
"\t\t\t\t\"vatpercent\": 20,\n" +
"\t\t\t\t\"reverseCharge\": false,\n" +
"\t\t\t\t\"intraCommunitySupply\": false\n" +
"\t\t},\n" +
"\t\t\t\"buyerOrderReferencedDocumentLineID\": \"3\",\n" +
"\t\t\t\"value\": 30\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"price\": 12,\n" +
"\t\t\t\"quantity\": 1,\n" +
"\t\t\t\"basisQuantity\": 1,\n" +
"\t\t\t\"product\": {\n" +
"\t\t\t\"unit\": \"C62\",\n" +
"\t\t\t\t\"name\": \"APPEL\",\n" +
"\t\t\t\t\"description\": \"Description\",\n" +
"\t\t\t\t\"taxCategoryCode\": \"S\",\n" +
"\t\t\t\t\"vatpercent\": 10,\n" +
"\t\t\t\t\"reverseCharge\": false,\n" +
"\t\t\t\t\"intraCommunitySupply\": false\n" +
"\t\t},\n" +
"\t\t\t\"buyerOrderReferencedDocumentLineID\": \"2\",\n" +
"\t\t\t\"value\": 12\n" +
"\t\t}\n" +
" ],\n" +
"\t\t\"ownStreet\": \"35 rue d'ici\",\n" +
"\t\t\"ownCountry\": \"FR\",\n" +
"\t\t\"ownZIP\": \"75018\",\n" +
"\t\t\"ownLocation\": \"PARIS\",\n" +
"\t\t\"ownVATID\": \"FR11123456782\",\n" +
"\t\t\"valid\": false\n" +
"\t}\n", Invoice.class);
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
zf2p.setProfile(Profiles.getByName("XRechnung"));
zf2p.generateXML(fromJSON);
theXML = new String(zf2p.getXML());
} catch (Exception e) {
exceptions = true;
}
assertTrue(theXML.contains("pour frais de recouvrement en cas de retard de paiement"));
assertFalse(exceptions);
}
}

View File

@@ -214,8 +214,10 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
public void testForeignImport() {
InputStream inputStream = this.getClass().getResourceAsStream("/zugferd_invoice.pdf");
ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream);
ZUGFeRDImporter zi = new ZUGFeRDImporter();
zi.doRecalculateItemPricesFromLineTotals();
zi.doIgnoreCalculationErrors();
zi.setInputStream(inputStream);
// Reading ZUGFeRD
String amount = zi.getAmount();

View File

@@ -137,7 +137,7 @@ public class ProfilesMinimumBasicWLTest extends TestCase {
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF_FX_MINIMUM_INV);
// Reading ZUGFeRD
assertEquals("145.37",zi.getAmount());
assertEquals("146.37",zi.getAmount());
// assertEquals(zi.getBIC(), ownBIC);
// assertEquals(zi.getIBAN(), ownIBAN);
assertEquals(ownOrgName, zi.getHolder());

View File

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

View File

@@ -129,19 +129,18 @@ public class XRTest extends TestCase {
Invoice readInvoice = new Invoice();
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
try {
zii.setRawXML(zf2p.getXML());
zii.setRawXML(zf2p.getXML(), false);
zii.extractInto(readInvoice);
} catch (ParseException | XPathExpressionException xp) {
fail("Exception not expected");
fail("ParseException not expected");
} catch (IOException e) {
throw new RuntimeException(e);
fail("IOException not expected");
}
List<FileAttachment> attachedFiles=zii.getFileAttachmentsXML();
FileAttachment[] attachedFiles=readInvoice.getAdditionalReferencedDocuments();
assertNotNull(attachedFiles);
assertEquals(attachedFiles.size(), 1);
assertEquals(attachedFiles.length, 1);
assertTrue(Arrays.equals(attachedFiles.get(0).getData(), b));
assertTrue(Arrays.equals(attachedFiles[0].getData(), b));
}

View File

@@ -22,6 +22,7 @@
package org.mustangproject.ZUGFeRD;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
@@ -29,6 +30,7 @@ import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import org.mustangproject.*;
import org.junit.FixMethodOrder;
@@ -61,9 +63,9 @@ public class ZF2PushTest extends TestCase {
final String TARGET_REVERSECHARGEPDF = "./target/testout-ZF2PushReverseCharge.pdf";
public void testPushExport() {
/***
* This writes to a filename like an official sample, please consider when changing (probably better not?)
*/
/***
* This writes to a filename like an official sample, please consider when changing (probably better not?)
*/
// the writing part
String orgname = "Bei Spiel GmbH";
String number = "RE-20201121/508";
@@ -88,6 +90,7 @@ public class ZF2PushTest extends TestCase {
.addItem(new Item(new Product("Design (hours)", "Of a sample invoice", "HUR", new BigDecimal(7)), price, new BigDecimal(1.0)))
.addItem(new Item(new Product("Ballons", "various colors, ~2000ml", "H87", new BigDecimal(19)), new BigDecimal("0.79"), new BigDecimal(400.0)))
.addItem(new Item(new Product("Hot air „heiße Luft“ (litres)", "", "LTR", new BigDecimal(19)), new BigDecimal("0.025"), new BigDecimal(800.0)))
.setRoundingAmount(new BigDecimal("1"))
);
ze.export(TARGET_PDF);
@@ -95,6 +98,15 @@ public class ZF2PushTest extends TestCase {
fail("Exception should not be raised");
}
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_PDF);
Invoice i = new Invoice();
try {
zii.extractInto(i);
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
} catch (ParseException e) {
throw new RuntimeException(e);
}
// now check the contents (like MustangReaderTest)
@@ -128,6 +140,7 @@ public class ZF2PushTest extends TestCase {
String senderDescription = "Kleinunternehmer";
String taxID = "9990815";
String theNote="oh lala";
BigDecimal price = new BigDecimal(priceStr);
try {
InputStream SOURCE_PDF = this.getClass().getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505blanko.pdf");
@@ -145,7 +158,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)))
.addItem(new Item(new Product("Testprodukt", "", "C62", 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"));
@@ -154,7 +167,7 @@ public class ZF2PushTest extends TestCase {
fail("IOException should not be raised");
}
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_ATTACHMENTSPDF);
Invoice i= null;
Invoice i = null;
try {
i = zii.extractInvoice();
} catch (XPathExpressionException e) {
@@ -162,7 +175,9 @@ public class ZF2PushTest extends TestCase {
} catch (ParseException e) {
throw new RuntimeException(e);
}
assertEquals(senderDescription,i.getSender().getDescription());
assertEquals(i.getZFItems()[0].getNotesWithSubjectCode().get(0).getContent(),theNote);
assertEquals(senderDescription, i.getSender().getDescription());
// now check the contents (like MustangReaderTest)
ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_ATTACHMENTSPDF);
@@ -233,6 +248,8 @@ public class ZF2PushTest extends TestCase {
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", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance().setPercent(new BigDecimal(50)))));
@@ -244,7 +261,7 @@ public class ZF2PushTest extends TestCase {
.setNumber(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1"))))
.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", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1))))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK")))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1))).addAllowance(new Allowance(new BigDecimal("1"))))
);
@@ -292,7 +309,7 @@ public class ZF2PushTest extends TestCase {
// .addItem(new Item(new Product("Testprodukt", "", "C62", 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"))
.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")))
.setDeliveryAddress(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0816"))
@@ -362,7 +379,7 @@ public class ZF2PushTest extends TestCase {
fail("IOException should not be raised");
}
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_INTRACOMMUNITYSUPPLYMANUALPDF);
Invoice i= null;
Invoice i = null;
try {
i = zii.extractInvoice();
} catch (XPathExpressionException e) {
@@ -520,11 +537,12 @@ 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)).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").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))
.setDeliveryDate(sdf.parse("2020-11-02")).setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE)
.setInvoiceReferencedDocumentID("abc123").addInvoiceReferencedDocument(new ReferencedDocument("abcd1234"))
);
} catch (ParseException e) {
e.printStackTrace();
@@ -552,7 +570,7 @@ public class ZF2PushTest extends TestCase {
assertTrue(zi.getUTF8().contains(occurrenceFrom));
assertTrue(zi.getUTF8().contains(occurrenceTo));
assertTrue(zi.getUTF8().contains(contractID));
assertEquals(zi.importedInvoice.getZFItems()[0].getId(), "a123");
assertTrue(zi.getUTF8().contains("20200113")); // to contain item delivery periods
assertTrue(zi.getUTF8().contains("20200115")); // to contain item delivery periods
@@ -568,6 +586,9 @@ public class ZF2PushTest extends TestCase {
try {
Invoice i = zii.extractInvoice();
assertEquals("abc123", i.getInvoiceReferencedDocumentID());
assertEquals(1, i.getInvoiceReferencedDocuments().size());
assertEquals("abcd1234", i.getInvoiceReferencedDocuments().get(0).getIssuerAssignedID());
assertEquals("4304171000002", i.getRecipient().getGlobalID());
assertEquals("2001015001325", i.getZFItems()[0].getProduct().getGlobalID());
assertEquals(orgID, i.getSender().getID());
@@ -784,4 +805,5 @@ public class ZF2PushTest extends TestCase {
match the read grand total */
}
}
}

View File

@@ -1,22 +1,24 @@
/** **********************************************************************
*
/**
* *********************************************************************
* <p>
* Copyright 2019 Jochen Staerk
*
* <p>
* Use is subject to license terms.
*
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* <p>
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
* <p>
* **********************************************************************
*/
package org.mustangproject.ZUGFeRD;
import java.io.IOException;
@@ -99,9 +101,9 @@ public class ZF2Test extends MustangReaderTestCase {
public IZUGFeRDExportableItem[] getZFItems() {
final Item[] allItems = new Item[3];
final Product designProduct = new Product("", "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung", "HUR",
new BigDecimal("7.000000"));
new BigDecimal("7.000000"));
final Product balloonProduct = new Product("", "Bestellerweiterung für E&F Umbau", "C62",
new BigDecimal("19.000000"));// test for issue 103
new BigDecimal("19.000000"));// test for issue 103
final Product airProduct = new Product("", "Heiße Luft pro Liter", "LTR", new BigDecimal("19.000000"));
allItems[0] = new Item(new BigDecimal("160"), new BigDecimal("1"), designProduct);
@@ -166,12 +168,12 @@ public class ZF2Test extends MustangReaderTestCase {
// the writing part
try (InputStream SOURCE_PDF = this.getClass()
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
.getResourceAsStream("/MustangGnuaccountingBeispielRE-20170509_505PDFA3.pdf");
ZUGFeRDExporterFromA3 ze = new ZUGFeRDExporterFromA3().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("EN16931")
.load(SOURCE_PDF)) {
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).setProfile("EN16931")
.load(SOURCE_PDF)) {
ze.setTransaction(this);
final String theXML = new String(ze.getProvider().getXML());
assertTrue(theXML.contains("<rsm:CrossIndustryInvoice"));
@@ -190,13 +192,13 @@ public class ZF2Test extends MustangReaderTestCase {
assertEquals(zi.getInvoiceID(), "RE-20170509/505");
assertEquals(zi.getZUGFeRDProfil(), "COMFORT");
assertEquals(zi.getInvoiceCurrencyCode(), "EUR");
assertEquals(zi.getIssuerAssignedID(),"");
assertEquals(zi.getIssuerAssignedID(), "");
assertEquals(zi.getIssueDate(), "20170509");
assertEquals(zi.getTaxPointDate(), "20170507");
assertEquals(zi.getPaymentTerms(), "Zahlbar ohne Abzug bis zum 30.05.2017");
assertEquals(zi.getLineTotalAmount(), "496.00");
assertEquals(zi.getTaxBasisTotalAmount(), "496.00");
assertEquals(zi.getTaxTotalAmount(),"75.04");
assertEquals(zi.getTaxTotalAmount(), "75.04");
assertEquals(zi.getRoundingAmount(), "");
assertEquals(zi.getPaidAmount(), "0.00");
assertEquals(zi.getBuyerTradePartyName(), "Theodor Est");
@@ -206,8 +208,8 @@ public class ZF2Test extends MustangReaderTestCase {
assertEquals(zi.getBuyertradePartySpecifiedTaxRegistrationID(), "DE999999999");
assertEquals(zi.getIncludedNote(), "");
assertEquals(zi.getHolder(), getOwnOrganisationName());
assertEquals(zi.getDocumentCode(),"380");
assertEquals(zi.getReference(),"AB321");
assertEquals(zi.getDocumentCode(), "380");
assertEquals(zi.getReference(), "AB321");
assertEquals(zi.getAmount(), "571.04");
assertEquals(zi.getBIC(), "COBADEFFXXX");
assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00");
@@ -244,7 +246,9 @@ public class ZF2Test extends MustangReaderTestCase {
// TODO Auto-generated catch block
e.printStackTrace();
}
} /**
}
/**
* The exporter test bases on @{code
* ./src/test/MustangBeispiel20221026.pdf}, adds
* metadata, writes to @{code ./target/testout-*} and then imports to check the
@@ -264,7 +268,7 @@ public class ZF2Test extends MustangReaderTestCase {
assertEquals("Innerhalb von 30 Tagen 2% Skonto, 60 Tage ohne Abzug", zi.getPaymentTerms());
assertEquals("804.35", zi.getLineTotalAmount());
assertEquals("809.34", zi.getTaxBasisTotalAmount());
assertEquals("153.77",zi.getTaxTotalAmount());
assertEquals("153.77", zi.getTaxTotalAmount());
assertEquals("", zi.getRoundingAmount());
assertEquals("0.00", zi.getPaidAmount());
assertEquals("Beispiel AG", zi.getBuyerTradePartyName());
@@ -273,8 +277,8 @@ public class ZF2Test extends MustangReaderTestCase {
assertEquals("10000", zi.getBuyerTradePartyID());
assertEquals("\n weclapp.com\nSomestreet 42\n08155 Some city\nDE\n ", zi.getIncludedNote());
assertEquals("weclapp.com", zi.getHolder());
assertEquals("380",zi.getDocumentCode());
assertEquals("01-95",zi.getReference());
assertEquals("380", zi.getDocumentCode());
assertEquals("01-95", zi.getReference());
assertEquals("RE1001", zi.getForeignReference());
assertEquals("54321", zi.getBuyerTradePartyAddress().getPostcodeCode());
assertEquals("Feldstraße 34", zi.getBuyerTradePartyAddress().getLineOne());
@@ -284,13 +288,13 @@ public class ZF2Test extends MustangReaderTestCase {
assertEquals("DE", zi.getBuyerTradePartyAddress().getCountryID());
assertEquals("Hithausen", zi.getBuyerTradePartyAddress().getCityName());
assertEquals("Beispiel Lager AG", zi.getDeliveryTradePartyName());
assertEquals("54321", zi.getDeliveryTradePartyAddress().getPostcodeCode());
assertEquals("Feldstraße 39", zi.getDeliveryTradePartyAddress().getLineOne());
assertEquals(null, zi.getDeliveryTradePartyAddress().getLineTwo());
assertEquals(null, zi.getDeliveryTradePartyAddress().getLineThree());
assertEquals(null, zi.getDeliveryTradePartyAddress().getCountrySubDivisionName());
assertEquals("DE", zi.getDeliveryTradePartyAddress().getCountryID());
assertEquals("Hithausen", zi.getDeliveryTradePartyAddress().getCityName());
assertEquals("54321", zi.getDeliveryTradePartyAddress().getPostcodeCode());
assertEquals("Feldstraße 39", zi.getDeliveryTradePartyAddress().getLineOne());
assertEquals(null, zi.getDeliveryTradePartyAddress().getLineTwo());
assertEquals(null, zi.getDeliveryTradePartyAddress().getLineThree());
assertEquals(null, zi.getDeliveryTradePartyAddress().getCountrySubDivisionName());
assertEquals("DE", zi.getDeliveryTradePartyAddress().getCountryID());
assertEquals("Hithausen", zi.getDeliveryTradePartyAddress().getCityName());
assertEquals("08155", zi.getSellerTradePartyAddress().getPostcodeCode());
assertEquals("Somestreet 42", zi.getSellerTradePartyAddress().getLineOne());
assertEquals(null, zi.getSellerTradePartyAddress().getLineTwo());

View File

@@ -1,4 +1,3 @@
/**
* *********************************************************************
* <p>
@@ -21,11 +20,19 @@
*/
package org.mustangproject.ZUGFeRD;
import org.mustangproject.FileAttachment;
import org.mustangproject.Invoice;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.StringUtils;
import org.junit.jupiter.api.Test;
import org.mustangproject.*;
import javax.xml.xpath.XPathExpressionException;
import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -33,6 +40,10 @@ import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
/***
@@ -65,6 +76,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
assertEquals("LTR", invoice.getZFItems()[2].getProduct().getUnit());
assertEquals("7.00", invoice.getZFItems()[0].getProduct().getVATPercent().toString());
assertEquals("RE-20170509/505", invoice.getNumber());
assertEquals("Zahlbar ohne Abzug bis zum 30.05.2017", invoice.getPaymentTermDescription());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
assertEquals("2017-05-09", sdf.format(invoice.getIssueDate()));
@@ -113,8 +125,10 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
// Reading ZUGFeRD
assertEquals("Bei Spiel GmbH", invoice.getOwnOrganisationName());
assertEquals(3, invoice.getZFItems().length);
assertEquals(invoice.getZFItems()[0].getNotesWithSubjectCode().get(0).getContent(),"Something");
assertEquals(invoice.getZFItems()[0].getNotesWithSubjectCode().size(),1);
assertEquals("400", invoice.getZFItems()[1].getQuantity().toString());
assertEquals("Zahlbar ohne Abzug bis zum 30.05.2017", invoice.getPaymentTermDescription());
assertEquals("AB321", invoice.getReferenceNumber());
assertEquals("160", invoice.getZFItems()[0].getPrice().toString());
assertEquals("Heiße Luft pro Liter", invoice.getZFItems()[2].getProduct().getName());
@@ -270,12 +284,16 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
public void testXRImport() {
boolean hasExceptions = false;
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
ZUGFeRDImporter zii = new ZUGFeRDImporter();
int version=-1;
try {
zii.fromXML(new String(Files.readAllBytes(Paths.get("./target/testout-XR-Edge.xml")), StandardCharsets.UTF_8));
version=zii.getVersion();
} catch (IOException e) {
hasExceptions = true;
} catch (Exception e) {
throw new RuntimeException(e);
}
Invoice invoice = null;
@@ -285,28 +303,43 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
hasExceptions = true;
}
assertFalse(hasExceptions);
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("1.00"), tc.getGrandTotal());
assertEquals(version,2);
assertTrue(new BigDecimal("1").compareTo(invoice.getZFItems()[0].getQuantity()) == 0);
LineCalculator lc=new LineCalculator(invoice.getZFItems()[0]);
assertTrue(new BigDecimal("1").compareTo(lc.getItemTotalNetAmount()) == 0);
assertTrue(invoice.getTradeSettlement().length == 1);
assertTrue(invoice.getTradeSettlement()[0] instanceof IZUGFeRDTradeSettlementPayment);
IZUGFeRDTradeSettlementPayment paym = (IZUGFeRDTradeSettlementPayment) invoice.getTradeSettlement()[0];
assertEquals("DE12500105170648489890", paym.getOwnIBAN());
assertEquals("COBADEFXXX", paym.getOwnBIC());
assertTrue(invoice.getPayee() != null);
assertEquals("VR Factoring GmbH", invoice.getPayee().getName());
}
/**
* testing if other files embedded in pdf additionally to the invoice can be read correctly
* */
*/
public void testDetach() {
boolean hasExceptions = false;
byte[] fileA=null;
byte[] fileB=null;
byte[] fileA = null;
byte[] fileB = null;
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushAttachments.pdf");
for (FileAttachment fa:zii.getFileAttachmentsPDF()) {
for (FileAttachment fa : zii.getFileAttachmentsPDF()) {
if (fa.getFilename().equals("one.pdf")) {
fileA=fa.getData();
fileA = fa.getData();
} else if (fa.getFilename().equals("two.pdf")) {
fileB=fa.getData();
fileB = fa.getData();
}
}
byte[] b = {12, 13}; // the sample data that was used to write the files
@@ -318,36 +351,127 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
}
/*
public void testEEISI_300_cii_Import() {
boolean hasExceptions = false;
File input = getResourceAsFile("not_validating_full_invoice_based_onTest_EeISI_300_CENfullmodel2.ubl.xml");
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
public void testImportDebit() {
File CIIinputFile = getResourceAsFile("cii/minimalDebit.xml");
try {
zii.fromXML(new String(Files.readAllBytes(input.toPath()), StandardCharsets.UTF_8));
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(CIIinputFile));
Invoice i = zii.extractInvoice();
assertEquals("DE21860000000086001055", i.getSender().getBankDetails().get(0).getIBAN());
ObjectMapper mapper = new ObjectMapper();
String jsonArray = mapper.writeValueAsString(i);
// assertEquals("",jsonArray);
} catch (IOException e) {
hasExceptions = true;
fail("IOException not expected");
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
} catch (ParseException e) {
throw new RuntimeException(e);
}
Invoice invoice = null;
try {
invoice = zii.extractInvoice();
assertEquals("Seller contact point",invoice.getSender().getName());
/*
<cbc:Name>Seller contact point</cbc:Name>
<cbc:Telephone>+41 345 654455</cbc:Telephone>
<cbc:ElectronicMail>seller@contact.de);*
} catch (XPathExpressionException | ParseException e) {
hasExceptions = true;
}
assertFalse(hasExceptions);
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("205.00"), tc.getGrandTotal());
}
*/
public void testImportMinimum() {
File CIIinputFile = getResourceAsFile("cii/facturFrMinimum.xml");
try {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(CIIinputFile));
CalculatedInvoice i = new CalculatedInvoice();
zii.extractInto(i);
assertEquals("671.15", i.getGrandTotal().toString());
} catch (IOException e) {
fail("IOException not expected");
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
@Test
public void testImportPrepaid() throws XPathExpressionException, ParseException {
InputStream inputStream = this.getClass()
.getResourceAsStream("/EN16931_1_Teilrechnung.pdf");
ZUGFeRDInvoiceImporter importer = new ZUGFeRDInvoiceImporter();
importer.doIgnoreCalculationErrors();
importer.setInputStream(inputStream);
CalculatedInvoice invoice = new CalculatedInvoice();
importer.extractInto(invoice);
boolean isBD=invoice.getTotalPrepaidAmount() instanceof BigDecimal;
assertTrue(isBD);
BigDecimal expectedPrepaid=new BigDecimal(50);
BigDecimal expectedLineTotal=new BigDecimal("180.76");
BigDecimal expectedDue=new BigDecimal("147.65");
if (isBD) {
BigDecimal amread=invoice.getTotalPrepaidAmount();
BigDecimal importedLineTotal=invoice.getLineTotalAmount();
BigDecimal importedDuePayable=invoice.getDuePayable();
assertTrue(amread.compareTo(expectedPrepaid) == 0);
assertTrue(importedLineTotal.compareTo(expectedLineTotal) == 0);
assertTrue(importedDuePayable.compareTo(expectedDue) == 0);
}
}
@Test
public void testImportIncludedNotes() throws XPathExpressionException, ParseException {
InputStream inputStream = this.getClass()
.getResourceAsStream("/EN16931_Einfach.pdf");
ZUGFeRDInvoiceImporter importer = new ZUGFeRDInvoiceImporter(inputStream);
Invoice invoice = importer.extractInvoice();
List<IncludedNote> notesWithSubjectCode = invoice.getNotesWithSubjectCode();
assertThat(notesWithSubjectCode).hasSize(2);
assertThat(notesWithSubjectCode.get(0).getSubjectCode()).isNull();
assertThat(notesWithSubjectCode.get(0).getContent()).isEqualTo("Rechnung gemäß Bestellung vom 01.11.2024.");
assertThat(notesWithSubjectCode.get(1).getSubjectCode()).isEqualTo(SubjectCode.REG);
assertThat(notesWithSubjectCode.get(1).getContent()).isEqualTo("Lieferant GmbH\t\t\t\t\n"
+ "Lieferantenstraße 20\t\t\t\t\n"
+ "80333 München\t\t\t\t\n"
+ "Deutschland\t\t\t\t\n"
+ "Geschäftsführer: Hans Muster\n"
+ "Handelsregisternummer: H A 123");
}
@Test
public void testImportPositionIncludedNotes() throws FileNotFoundException, XPathExpressionException, ParseException {
File inputFile = getResourceAsFile("ZTESTZUGFERD_1_INVDSS_012015738820PDF-1.pdf");
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(inputFile));
Invoice invoice = zii.extractInvoice();
assertEquals(1, invoice.getZFItems().length);
assertEquals(8, invoice.getZFItems()[0].getNotesWithSubjectCode().size());
assertEquals("FB-LE 9999", invoice.getZFItems()[0].getNotesWithSubjectCode().stream().filter(note -> note.getSubjectCode().equals(SubjectCode.ABZ)).findFirst().get().getContent());
}
@Test
public void testImportXRechnungPositionNote() throws FileNotFoundException, XPathExpressionException, ParseException {
File inputFile = getResourceAsFile("TESTXRECHNUNG_INVDSS_012015776085.XML");
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(inputFile));
Invoice invoice = zii.extractInvoice();
assertEquals(1, invoice.getZFItems().length);
assertFalse(invoice.getZFItems()[0].getNotes() == null);
assertEquals(1, invoice.getZFItems()[0].getNotes().length);
}
@Test
public void testImportXRechnungWithoutCalculationErrors() throws FileNotFoundException, XPathExpressionException, ParseException {
File inputFile = getResourceAsFile("cii/02.03a-INVOICE_uncefact.xml");
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(inputFile));
assertEquals("0", zii.importedInvoice.getDuePayable().toPlainString());
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?><ubl:Invoice xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2 http://docs.oasis-open.org/ubl/os-UBL-2.1/xsd/maindoc/UBL-Invoice-2.1.xsd">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>2015776085</cbc:ID>
<cbc:IssueDate>2024-11-01</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:Note>#AAI# Wenn bereits bezahlt, nur zu den Akten legen. Für Verzug und Verzugszinsen gelten die Bestimmungen der §§ 286 - 288 BGB. Der Schuldner einer Entgeltforderung kommt spätestens in Verzug, wenn er nicht innerhalb von 30 Tagen nach Fälligkeit und Zugang einer Rechnung oder gleichwertigen Zahlungsaufstellung leistet. Die Lieferung von Waren und Fahrzeugen erfolgt unter Eigentumsvorbehalt.</cbc:Note>
<cbc:Note>#PAI# Rechnungsbetrag zahlbar ohne Abzug sofort nach Erhalt der Rechnung.</cbc:Note>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cbc:BuyerReference>02-ZZ987654-99</cbc:BuyerReference>
<cac:InvoicePeriod>
<cbc:StartDate>2024-11-01</cbc:StartDate>
<cbc:EndDate>2024-11-30</cbc:EndDate>
</cac:InvoicePeriod>
<cac:OrderReference>
<cbc:ID>N/A</cbc:ID>
</cac:OrderReference>
<cac:ContractDocumentReference>
<cbc:ID>63435555</cbc:ID>
</cac:ContractDocumentReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="9930">DE238574172</cbc:EndpointID>
<cac:PartyName>
<cbc:Name>Alphabet Fuhrparkmanagement GmbH</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Lilienthalallee 26</cbc:StreetName>
<cbc:CityName>München</cbc:CityName>
<cbc:PostalZone>80786</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE238574172</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Alphabet Fuhrparkmanagement GmbH</cbc:RegistrationName>
<cbc:CompanyID>HRB 181098</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>Yildiz Tolga</cbc:Name>
<cbc:Telephone>+49899--</cbc:Telephone>
<cbc:ElectronicMail>Tolga.Yildiz@alphabet.de</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="9930">N/A</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID>00987654</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Muster GmbH</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Musterweg 1</cbc:StreetName>
<cbc:CityName>Kiel</cbc:CityName>
<cbc:PostalZone>24105</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Muster GmbH</cbc:RegistrationName>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>Mustermann Max</cbc:Name>
</cac:Contact>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:Delivery>
<cbc:ActualDeliveryDate>2024-11-30</cbc:ActualDeliveryDate>
<cac:DeliveryLocation>
<cbc:ID>00987654</cbc:ID>
<cac:Address>
<cbc:StreetName>Musterweg 1</cbc:StreetName>
<cbc:CityName>Kiel</cbc:CityName>
<cbc:PostalZone>24105</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:Address>
</cac:DeliveryLocation>
<cac:DeliveryParty>
<cac:PartyName>
<cbc:Name>Muster GmbH</cbc:Name>
</cac:PartyName>
</cac:DeliveryParty>
</cac:Delivery>
<cac:PaymentMeans>
<cbc:PaymentMeansCode>30</cbc:PaymentMeansCode>
<cac:PayeeFinancialAccount>
<cbc:ID>DE34700700100156919301</cbc:ID>
<cbc:Name>Alphabet Fuhrparkmanagement GmbH</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>DEUTDEMMXXX</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
</cac:PaymentMeans>
<cac:PaymentTerms>
<cbc:Note>Rechnungsbetrag zahlbar ohne Abzug sofort nach Erhalt der Rechnung.</cbc:Note>
</cac:PaymentTerms>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">161.69</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">851.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">161.69</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">851.00</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">851.00</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">1012.69</cbc:TaxInclusiveAmount>
<cbc:PayableAmount currencyID="EUR">1012.69</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:Note>#AAI# Finanzrate vom 01.11.2024 bis 30.11.2024 #ABZ/Kennzeichen#SH-9 18E #AKG/Fahrgestellnummer#WBY51EJ080CR55555 #BA/Kilometerstand#0 #AKV/LeasingNr#63435555</cbc:Note>
<cbc:InvoicedQuantity unitCode="C62">1.00</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">851.00</cbc:LineExtensionAmount>
<cac:InvoicePeriod>
<cbc:StartDate>2024-11-01</cbc:StartDate>
<cbc:EndDate>2024-11-30</cbc:EndDate>
</cac:InvoicePeriod>
<cac:Item>
<cbc:Description>FL-Rate</cbc:Description>
<cbc:Name>FL-Rate</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>90101</cbc:ID>
</cac:SellersItemIdentification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">851.00</cbc:PriceAmount>
<cbc:BaseQuantity>1.00</cbc:BaseQuantity>
</cac:Price>
</cac:InvoiceLine>
</ubl:Invoice>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,56 @@
<?xml version='1.0' encoding='UTF-8'?>
<rsm:CrossIndustryInvoice xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:factur-x.eu:1p0:minimum</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>FA-2017-0010</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20171113</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>Au bon moulin</ram:Name>
<ram:SpecifiedLegalOrganization>
<ram:ID schemeID="0002">99999999800010</ram:ID>
</ram:SpecifiedLegalOrganization>
<ram:PostalTradeAddress>
<ram:CountryID>FR</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">FR11999999998</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Ma jolie boutique</ram:Name>
<ram:SpecifiedLegalOrganization>
<ram:ID schemeID="0002">78787878400035</ram:ID>
</ram:SpecifiedLegalOrganization>
<ram:PostalTradeAddress>
<ram:CountryID>FR</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">FR19787878784</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
<ram:BuyerOrderReferencedDocument>
<ram:IssuerAssignedID>PO445</ram:IssuerAssignedID>
</ram:BuyerOrderReferencedDocument>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery/>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:TaxBasisTotalAmount currencyID="EUR">624.90</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">46.25</ram:TaxTotalAmount>
<ram:GrandTotalAmount currencyID="EUR">671.15</ram:GrandTotalAmount>
<ram:DuePayableAmount currencyID="EUR">470.15</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>

View File

@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100">
<!-- generated by: mustangproject.org vnull-->
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>471102</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20180304</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Trennblätter A4</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>9.9000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="H87">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">20.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>198.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>2</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Joghurt Banane</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>5.5000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="H87">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">50.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>275.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>Lieferant GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>80333</ram:PostcodeCode>
<ram:LineOne>Lieferantenstraße 20</ram:LineOne>
<ram:CityName>München</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE123456789</ram:ID>
</ram:SpecifiedTaxRegistration>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="FC">201/113/40209</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Kunden AG Mitte</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>69876</ram:PostcodeCode>
<ram:LineOne>Kundenstraße 15</ram:LineOne>
<ram:CityName>Frankfurt</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20180304</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:CreditorReferenceID>DE98ZZZ09999999999</ram:CreditorReferenceID>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementPaymentMeans>
<ram:TypeCode>59</ram:TypeCode>
<ram:PayerPartyDebtorFinancialAccount>
<ram:IBANID>DE21860000000086001055</ram:IBANID></ram:PayerPartyDebtorFinancialAccount>
</ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>19.25</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>275.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>37.62</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>198.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Der Betrag in Höhe von EUR 529,87 wird am 20.03.2018 von Ihrem Konto per SEPA-Lastschrift eingezogen.
</ram:Description>
<ram:DirectDebitMandateID>REF A-123</ram:DirectDebitMandateID>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>473.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>473.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">56.87</ram:TaxTotalAmount>
<ram:GrandTotalAmount>529.87</ram:GrandTotalAmount>
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
<ram:DuePayableAmount>529.87</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>

View File

@@ -0,0 +1,430 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- English disclaimer below.-->
<!--Nutzungsrechte
ZUGFeRD Datenformat Version 2.3.0, 18.09.2024
Beispiel Version 18.09.2024
Zweck des Forums elektronisch Rechnung Deutschland, welches am 31. März 2010 unter der Arbeitsgemeinschaft für
wirtschaftliche Verwaltung e. V. gegründet wurde, ist u. a. die Schaffung und Spezifizierung eines offenen Datenformats
für strukturierten elektronischen Datenaustausch auf der Grundlage offener und nicht diskriminierender, standardisierter
Technologien („ZUGFeRD Datenformat“).
Das ZUGFeRD Datenformat wird nach Maßgabe des FeRD sowohl Unternehmen als auch der öffentlichen Verwaltung
frei zugänglich gemacht. Hierfür bietet FeRD allen Unternehmen und Organisationen der öffentlichen Verwaltung eine
Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD-Datenformats zu fairen, sachgerechten und nicht
diskriminierenden Bedingungen an.
Die Spezifikation des FeRD zur Implementierung des ZUGFeRD Datenformats ist in ihrer jeweils geltenden Fassung
abrufbar unter www.ferd-net.de.
Im Einzelnen schließt die Nutzungsgewährung ein:
=====================================
FeRD räumt eine Lizenz für die Nutzung des urheberrechtlich geschützten ZUGFeRD Datenformats in der jeweils
geltenden und akzeptierten Fassung (www.ferd-net.de) ein.
Die Lizenz beinhaltet ein unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung,
Weiterbearbeitung und Verbindung mit anderen Produkten.
Die Lizenz gilt insbesondere für die Entwicklung, die Gestaltung, die Herstellung, den Verkauf, die Nutzung oder
anderweitige Verwendung des ZUGFeRD Datenformats für Hardware- und/oder Softwareprodukte sowie sonstige
Anwendungen und Dienste.
Diese Lizenz schließt nicht die wesentlichen Patente der Mitglieder von FeRD ein. Als wesentliche Patente sind Patente
und Patentanmeldungen weltweit zu verstehen, die einen oder mehrere Patentansprüche beinhalten, bei denen es sich um
notwendige Ansprüche handelt. Notwendige Ansprüche sind lediglich jene Ansprüche der Wesentlichen Patente, die durch
die Implementierung des ZUGFeRD Datenformats notwendigerweise verletzt würden.
Der Lizenznehmer ist berechtigt, seinen jeweiligen Konzerngesellschaften ein unbefristetes, weltweites, nicht übertragbares,
unwiderrufliches Nutzungsrecht einschließlich des Rechts der Weiterentwicklung, Weiterbearbeitung und Verbindung mit
anderen Produkten einzuräumen.
Die Lizenz wird kostenfrei zur Verfügung gestellt.
Außer im Falle vorsätzlichen Verschuldens oder grober Fahrlässigkeit haftet FeRD weder für Nutzungsausfall, entgangenen
Gewinn, Datenverlust, Kommunikationsverlust, Einnahmeausfall, Vertragseinbußen, Geschäftsausfall oder für Kosten,
Schäden, Verluste oder Haftpflichten im Zusammenhang mit einer Unterbrechung der Geschäftstätigkeit, noch für konkrete,
beiläufig entstandene, mittelbare Schäden, Straf- oder Folgeschäden und zwar auch dann nicht, wenn die Möglichkeit der
Kosten, Verluste bzw. Schäden hätte normalerweise vorhergesehen werden können.-->
<!--Right of use
ZUGFeRD Data format version 2.3.0, September 18th, 2024
The purpose of the Forum elektronische Rechnung Deutschland (FeRD), which was founded on March 31, 2010 under the
umbrella of Arbeitsgemeinschaft für wirtschaftliche Verwaltung e. V., is, among other things, to create and specify an
open data format for structured electronic data exchange on the basis of open and non discriminatory, standardised
technologies ("ZUGFeRD data format").
The ZUGFeRD data format is used by both companies and public administration according to the FeRD
made freely accessible. For this purpose FeRD offers all companies and organisations of the public administration a
License to use the copyrighted ZUGFeRD data format in a fair, appropriate and non
discriminatory conditions.
The specification of the FeRD for the implementation of the ZUGFeRD data format is, in its currently valid version
available at www.ferd-net.de.
In detail, the grant of use includes
=====================================
FeRD grants a license for the use of the copyrighted ZUGFeRD data format in the respective
valid and accepted version (www.ferd-net.de).
The license includes an irrevocable right of use including the right of further development,
Further processing and connection with other products.
The license applies in particular to the development, design, production, sale, use or
other use of the ZUGFeRD data format for hardware and/or software products and other
applications and services.
This license does not include the essential patents of the members of FeRD. The essential patents are patents
and patent applications worldwide which contain one or more claims that are
necessary claims. Necessary claims are only those claims of the essential patents which are
the implementation of the ZUGFeRD data format would necessarily be violated.
The Licensee is entitled to provide its respective group companies with an unlimited, worldwide, non-transferable,
irrevocable right of use including the right of further development, further processing and connection with
other products.
The license is provided free of charge.
Except in the case of intentional fault or gross negligence, FeRD is not liable for loss of use, loss of
Profit, loss of data, loss of communication, loss of revenue, loss of contracts, loss of business or for costs
damages, losses or liabilities in connection with an interruption of business, nor for concrete,
incidental, indirect, punitive or consequential damages, even if the possibility of
costs, losses or damages could normally have been foreseen.-->
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:TestIndicator>
<udt:Indicator>true</udt:Indicator>
</ram:TestIndicator>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>KR87654321012</ram:ID>
<ram:Name>KOSTENRECHNUNG</ram:Name>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20241115</udt:DateTimeString>
</ram:IssueDateTime>
<ram:IncludedNote>
<ram:ContentCode>ST3</ram:ContentCode>
<ram:Content>Es bestehen Rabatt- oder Bonusvereinbarungen.</ram:Content>
<ram:SubjectCode>AAK</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:ContentCode>EEV</ram:ContentCode>
<ram:Content>Der Verkäufer bleibt Eigentümer der Waren bis zur vollständigen Erfüllung der Kaufpreisforderung.</ram:Content>
<ram:SubjectCode>AAJ</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>MUSTERLIEFERANT GMBH
BAHNHOFSTRASSE 99
99199 MUSTERHAUSEN
Geschäftsführung:
Max Mustermann
USt-IdNr: DE123456789
Telefon: +49 932 431 0
www.musterlieferant.de
HRB Nr. 372876
Amtsgericht Musterstadt
GLN 4304171000002
</ram:Content>
<ram:SubjectCode>REG</ram:SubjectCode>
</ram:IncludedNote>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0088">4123456000014</ram:GlobalID>
<ram:SellerAssignedID>WA997</ram:SellerAssignedID>
<ram:Name>Wirkarbeit HT</ram:Name>
<ram:ApplicableProductCharacteristic>
<ram:Description>Zählpunkt</ram:Description>
<ram:Value>DE0001346484600000000000000100038</ram:Value>
</ram:ApplicableProductCharacteristic>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>0.0520</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>0.0520</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="KWH">1000.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>52.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>2</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0088">4123456000021</ram:GlobalID>
<ram:SellerAssignedID>ÖST250</ram:SellerAssignedID>
<ram:Name>Ökosteuer Lieferant</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>0.0205</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>0.0205</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="KWH">1000.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.50</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>3</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0088">4260331811362</ram:GlobalID>
<ram:Name>Kommissionierer 1250032 D. Muster</ram:Name>
<ram:Description>Besteller: Hr. Mayer, Personalnr. 4488</ram:Description>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>15.0000</ram:ChargeAmount>
<ram:AppliedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:ActualAmount>4.50</ram:ActualAmount>
<ram:Reason>Artikelrabatt 1</ram:Reason>
</ram:AppliedTradeAllowanceCharge>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>10.5000</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="HUR">27.5000</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>288.75</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>4</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0088">2001015001325</ram:GlobalID>
<ram:SellerAssignedID>FB05</ram:SellerAssignedID>
<ram:Name>FALTENBEUTEL 16x6x28 CM</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>0.0105</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>0.0105</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">3500.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>36.75</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>5</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0088">4123456000038</ram:GlobalID>
<ram:SellerAssignedID>KOP05</ram:SellerAssignedID>
<ram:Name>Kopierpapier A4</ram:Name>
<ram:Description>Zählerstand von-bis: 543210 - 544420</ram:Description>
<ram:ApplicableProductCharacteristic>
<ram:Description>Zähler-Nr.</ram:Description>
<ram:Value>MG-X79318</ram:Value>
</ram:ApplicableProductCharacteristic>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>0.0100</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>0.0100</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">1210.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>12.10</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:ID>549910</ram:ID>
<ram:GlobalID schemeID="0088">4333741000005</ram:GlobalID>
<ram:Name>MUSTERLIEFERANT GMBH</ram:Name>
<ram:DefinedTradeContact>
<ram:TelephoneUniversalCommunication>
<ram:CompleteNumber>+49 932 431 500</ram:CompleteNumber>
</ram:TelephoneUniversalCommunication>
<ram:EmailURIUniversalCommunication>
<ram:URIID>max.mustermann@musterlieferant.de</ram:URIID>
</ram:EmailURIUniversalCommunication>
</ram:DefinedTradeContact>
<ram:PostalTradeAddress>
<ram:PostcodeCode>99199</ram:PostcodeCode>
<ram:LineOne>BAHNHOFSTRASSE 99</ram:LineOne>
<ram:CityName>MUSTERHAUSEN</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="FC">201/113/40209</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:ID>339420</ram:ID>
<ram:GlobalID schemeID="0088">4304171000002</ram:GlobalID>
<ram:Name>MUSTER-KUNDE GMBH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>40235</ram:PostcodeCode>
<ram:LineOne>KUNDENWEG 88</ram:LineOne>
<ram:CityName>DUESSELDORF</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
</ram:BuyerTradeParty>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>A777123</ram:IssuerAssignedID>
<ram:TypeCode>130</ram:TypeCode>
</ram:AdditionalReferencedDocument>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ShipToTradeParty>
<ram:GlobalID schemeID="0088">4304171088093</ram:GlobalID>
<ram:Name>MUSTER-MARKT</ram:Name>
<ram:DefinedTradeContact>
<ram:DepartmentName>7322</ram:DepartmentName>
</ram:DefinedTradeContact>
<ram:PostalTradeAddress>
<ram:PostcodeCode>31157</ram:PostcodeCode>
<ram:LineOne>HAUPTSTRASSE 44</ram:LineOne>
<ram:CityName>SARSTEDT</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
</ram:ShipToTradeParty>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20241030</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
<ram:DeliveryNoteReferencedDocument>
<ram:IssuerAssignedID>L87654321012</ram:IssuerAssignedID>
<ram:FormattedIssueDateTime>
<qdt:DateTimeString format="102">20241031</qdt:DateTimeString>
</ram:FormattedIssueDateTime>
</ram:DeliveryNoteReferencedDocument>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:InvoiceeTradeParty>
<ram:ID>339420</ram:ID>
<ram:GlobalID schemeID="0088">4304171000002</ram:GlobalID>
<ram:Name>MUSTER-KUNDE GMBH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>40235</ram:PostcodeCode>
<ram:LineOne>KUNDENWEG 88</ram:LineOne>
<ram:CityName>DUESSELDORF</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
</ram:InvoiceeTradeParty>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>76.67</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>403.55</ram:BasisAmount>
<ram:LineTotalBasisAmount>410.10</ram:LineTotalBasisAmount>
<ram:AllowanceChargeBasisAmount>-6.55</ram:AllowanceChargeBasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:BasisAmount>410.10</ram:BasisAmount>
<ram:ActualAmount>21.55</ram:ActualAmount>
<ram:Reason>Sonderrabatt</ram:Reason>
<ram:CategoryTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:CategoryTradeTax>
</ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedLogisticsServiceCharge>
<ram:Description>Transportkosten: Frachbetrag</ram:Description>
<ram:AppliedAmount>15.00</ram:AppliedAmount>
<ram:AppliedTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:AppliedTradeTax>
</ram:SpecifiedLogisticsServiceCharge>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Skontovereinbarung: 2% bei Zahlung innerhalb 10 Tagen nach Rechnungsdatum</ram:Description>
<ram:ApplicableTradePaymentDiscountTerms>
<ram:BasisPeriodMeasure unitCode="DAY">10</ram:BasisPeriodMeasure>
<ram:CalculationPercent>2.00</ram:CalculationPercent>
</ram:ApplicableTradePaymentDiscountTerms>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>410.10</ram:LineTotalAmount>
<ram:ChargeTotalAmount>15.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>21.55</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>403.55</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">76.67</ram:TaxTotalAmount>
<ram:GrandTotalAmount>480.22</ram:GrandTotalAmount>
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
<ram:DuePayableAmount>480.22</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>

File diff suppressed because it is too large Load Diff

View File

@@ -1555,7 +1555,7 @@
<div class="boxzeile">
<div class="boxdaten legende ">Description:</div>
<div id="BT-154" title="BT-154" class="boxdaten wert">Processor: Intel Core 2 Duo SU9400 LV (1.4GHz). RAM:
3MB. Screen 1440x900</div>
3MB. Screen 1440x900</div>
</div>
<div class="boxzeile">
<div class="boxdaten legende ">Part number:</div>
@@ -2354,6 +2354,10 @@
<div class="boxdaten legende">Dispatch note ID:</div>
<div id="BT-16" title="BT-16" class="boxdaten wert"></div>
</div>
<div class="boxzeile">
<div class="boxdaten legende">Delivery note ID:</div>
<div id="BT-X-202" title="BT-X-202" class="boxdaten wert"></div>
</div>
<div class="boxzeile">
<div class="boxdaten legende">Process ID:</div>
<div id="BT-23" title="BT-23" class="boxdaten wert"></div>
@@ -2625,4 +2629,4 @@ function downloadData (element_id) {
});
//
</script></html>
</script></html>

View File

@@ -1219,8 +1219,6 @@
</div>
</div>
</div>
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig"></div>
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig"></div>
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig first">
<div class="boxzeile">
<div id="uebersichtZahlungsinformationen" class="box subBox">
@@ -1754,6 +1752,10 @@
<div class="boxdaten legende">Dispatch note ID:</div>
<div id="BT-16" title="BT-16" class="boxdaten wert"></div>
</div>
<div class="boxzeile">
<div class="boxdaten legende">Delivery note ID:</div>
<div id="BT-X-202" title="BT-X-202" class="boxdaten wert"></div>
</div>
<div class="boxzeile">
<div class="boxdaten legende">Process ID:</div>
<div id="BT-23" title="BT-23" class="boxdaten wert"></div>
@@ -1946,4 +1948,4 @@ function downloadData (element_id) {
});
//
</script></html>
</script></html>

View File

@@ -1250,8 +1250,6 @@
</div>
</div>
</div>
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig"></div>
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig"></div>
<div class="boxtabelle boxabstandtop boxtabelleZweispaltig first">
<div class="boxzeile">
<div id="uebersichtZahlungsinformationen" class="box subBox">
@@ -1926,6 +1924,10 @@
<div class="boxdaten legende">Identifiant du bordereau d'expédition:</div>
<div id="BT-16" title="BT-16" class="boxdaten wert"></div>
</div>
<div class="boxzeile">
<div class="boxdaten legende">Identifiant du bon de livraison:</div>
<div id="BT-X-202" title="BT-X-202" class="boxdaten wert"></div>
</div>
<div class="boxzeile">
<div class="boxdaten legende">Identifiant processus:</div>
<div id="BT-23" title="BT-23" class="boxdaten wert"></div>
@@ -2118,4 +2120,4 @@ function downloadData (element_id) {
});
//
</script></html>
</script></html>

View File

@@ -1,411 +1,411 @@
<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:BusinessProcessSpecifiedDocumentContextParameter>
<ram:ID>BT-23 Business Process Type</ram:ID>
</ram:BusinessProcessSpecifiedDocumentContextParameter>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>Test_EeISI_100</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20181112</udt:DateTimeString>
</ram:IssueDateTime>
<ram:IncludedNote>
<ram:Content>invoice note text</ram:Content>
<ram:SubjectCode>#AAA#</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>invoice note text 2</ram:Content>
<ram:SubjectCode>#AAA#</ram:SubjectCode>
</ram:IncludedNote>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1a</ram:LineID>
<ram:IncludedNote>
<ram:Content>Invoice line note</ram:Content>
</ram:IncludedNote>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID>Item standar identifier</ram:GlobalID>
<ram:SellerAssignedID>Item seller's identifier</ram:SellerAssignedID>
<ram:BuyerAssignedID>Item buyer's identifier</ram:BuyerAssignedID>
<ram:Name>Item name</ram:Name>
<ram:Description>Item description</ram:Description>
<ram:ApplicableProductCharacteristic>
<ram:Description>Color</ram:Description>
<ram:Value>Red</ram:Value>
</ram:ApplicableProductCharacteristic>
<ram:ApplicableProductCharacteristic>
<ram:Description>Size</ram:Description>
<ram:Value>L</ram:Value>
</ram:ApplicableProductCharacteristic>
<ram:DesignatedProductClassification>
<ram:ClassCode listID="ZZZ" listVersionID="version0">Item classification identifier0</ram:ClassCode>
</ram:DesignatedProductClassification>
<ram:OriginTradeCountry>
<ram:ID>IT</ram:ID>
</ram:OriginTradeCountry>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:BuyerOrderReferencedDocument>
<ram:LineID>12345</ram:LineID>
</ram:BuyerOrderReferencedDocument>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>11.00</ram:ChargeAmount>
<ram:BasisQuantity unitCode="EA">1.00</ram:BasisQuantity>
<ram:AppliedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:ActualAmount>1.00</ram:ActualAmount>
</ram:AppliedTradeAllowanceCharge>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>10.00</ram:ChargeAmount>
<ram:BasisQuantity unitCode="EA">1.00</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="EA">10.00</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>5.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:BillingSpecifiedPeriod>
<ram:StartDateTime>
<rsm:ExchangedDocumentContext>
<ram:BusinessProcessSpecifiedDocumentContextParameter>
<ram:ID>BT-23 Business Process Type</ram:ID>
</ram:BusinessProcessSpecifiedDocumentContextParameter>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>Test_EeISI_100</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20181112</udt:DateTimeString>
</ram:StartDateTime>
<ram:EndDateTime>
<udt:DateTimeString format="102">20181130</udt:DateTimeString>
</ram:EndDateTime>
</ram:BillingSpecifiedPeriod>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>55</ram:ReasonCode>
<ram:Reason>Invoice line allowance reason</ram:Reason>
</ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>true</udt:Indicator>
</ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>AAA</ram:ReasonCode>
<ram:Reason>Invoice line charge reason</ram:Reason>
</ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>1000.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>Line object identifier</ram:IssuerAssignedID>
<ram:TypeCode>130</ram:TypeCode>
<ram:ReferenceTypeCode />
</ram:AdditionalReferencedDocument>
<ram:ReceivableSpecifiedTradeAccountingAccount>
<ram:ID>6789</ram:ID>
</ram:ReceivableSpecifiedTradeAccountingAccount>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1b</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Item name 2</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>10.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="EA">10.00</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>E</ram:CategoryCode>
<ram:RateApplicablePercent>0.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>1000.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:BuyerReference>123</ram:BuyerReference>
<ram:SellerTradeParty>
<ram:GlobalID schemeID="0100">Seller identifier 1</ram:GlobalID>
<ram:GlobalID schemeID="0110">Seller identifier 2</ram:GlobalID>
<ram:Name>Seller name</ram:Name>
<ram:Description>Seller additional legal information</ram:Description>
<ram:SpecifiedLegalOrganization>
<ram:ID schemeID="0310">Seller legal identifier</ram:ID>
<ram:TradingBusinessName>Seller trading name</ram:TradingBusinessName>
</ram:SpecifiedLegalOrganization>
<ram:DefinedTradeContact>
<ram:PersonName>Seller contact point</ram:PersonName>
<ram:TelephoneUniversalCommunication>
<ram:CompleteNumber>+41 345 654455</ram:CompleteNumber>
</ram:TelephoneUniversalCommunication>
<ram:EmailURIUniversalCommunication>
<ram:URIID>seller@contact.de</ram:URIID>
</ram:EmailURIUniversalCommunication>
</ram:DefinedTradeContact>
<ram:PostalTradeAddress>
<ram:PostcodeCode>12345</ram:PostcodeCode>
<ram:LineOne>Seller address line 1</ram:LineOne>
<ram:LineTwo>Seller address line 2</ram:LineTwo>
<ram:LineThree>Seller address line 3</ram:LineThree>
<ram:CityName>Seller city</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
<ram:CountrySubDivisionName>Seller country subdivision</ram:CountrySubDivisionName>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID schemeID="SMTP">Seller electronic address</ram:URIID>
</ram:URIUniversalCommunication>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE12345677</ram:ID>
</ram:SpecifiedTaxRegistration>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="FC">DE49294093</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:GlobalID schemeID="0190">Buyer identifier</ram:GlobalID>
<ram:Name>Buyer name</ram:Name>
<ram:SpecifiedLegalOrganization>
<ram:ID schemeID="0089">Buyer legal registration identifier</ram:ID>
<ram:TradingBusinessName>Buyer trading name</ram:TradingBusinessName>
</ram:SpecifiedLegalOrganization>
<ram:DefinedTradeContact>
<ram:PersonName>Buyer contact point</ram:PersonName>
<ram:TelephoneUniversalCommunication>
<ram:CompleteNumber>+353 2948584</ram:CompleteNumber>
</ram:TelephoneUniversalCommunication>
<ram:EmailURIUniversalCommunication>
<ram:URIID>buyer@contact.ie</ram:URIID>
</ram:EmailURIUniversalCommunication>
</ram:DefinedTradeContact>
<ram:PostalTradeAddress>
<ram:PostcodeCode>34562</ram:PostcodeCode>
<ram:LineOne>Buyer address line 1</ram:LineOne>
<ram:LineTwo>Buyer address line 2</ram:LineTwo>
<ram:LineThree>Buyer address line 3</ram:LineThree>
<ram:CityName>Buyer city</ram:CityName>
<ram:CountryID>IE</ram:CountryID>
<ram:CountrySubDivisionName>Buyer country subdivision</ram:CountrySubDivisionName>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID schemeID="DE:SMTP">Buyer electronic address</ram:URIID>
</ram:URIUniversalCommunication>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">IE394838894</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
<ram:SellerTaxRepresentativeTradeParty>
<ram:Name>Tax representative name</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>23455</ram:PostcodeCode>
<ram:LineOne>Tax representative address line 1</ram:LineOne>
<ram:LineTwo>Tax representative address line 2</ram:LineTwo>
<ram:LineThree>Tax representative address line 3</ram:LineThree>
<ram:CityName>Tax representative city</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
<ram:CountrySubDivisionName>Tax representative country subdivision</ram:CountrySubDivisionName>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE3949053</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTaxRepresentativeTradeParty>
<ram:SellerOrderReferencedDocument>
<ram:IssuerAssignedID>def</ram:IssuerAssignedID>
</ram:SellerOrderReferencedDocument>
<ram:BuyerOrderReferencedDocument>
<ram:IssuerAssignedID>abc</ram:IssuerAssignedID>
</ram:BuyerOrderReferencedDocument>
<ram:ContractReferencedDocument>
<ram:IssuerAssignedID>789</ram:IssuerAssignedID>
</ram:ContractReferencedDocument>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>Supporting document ref</ram:IssuerAssignedID>
<ram:URIID>External document location</ram:URIID>
<ram:TypeCode>916</ram:TypeCode>
<ram:Name>Supporting document descr</ram:Name>
<ram:AttachmentBinaryObject mimeCode="application/pdf" filename="filename0">ZGVmYXVsdA==</ram:AttachmentBinaryObject>
</ram:AdditionalReferencedDocument>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>rst</ram:IssuerAssignedID>
<ram:TypeCode>130</ram:TypeCode>
<ram:ReferenceTypeCode>0090</ram:ReferenceTypeCode>
</ram:AdditionalReferencedDocument>
<ram:SpecifiedProcuringProject>
<ram:ID>456</ram:ID>
<ram:Name>Project reference</ram:Name>
</ram:SpecifiedProcuringProject>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ShipToTradeParty>
<ram:GlobalID schemeID="0045">deliver location identifier</ram:GlobalID>
<ram:Name>Deliver to party name</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>98765</ram:PostcodeCode>
<ram:LineOne>Deliver to address line 1</ram:LineOne>
<ram:LineTwo>Deliver to address line 2</ram:LineTwo>
<ram:LineThree>Deliver to address line 3</ram:LineThree>
<ram:CityName>Deliver to city</ram:CityName>
<ram:CountryID>IE</ram:CountryID>
<ram:CountrySubDivisionName>Deliver to country subdivision</ram:CountrySubDivisionName>
</ram:PostalTradeAddress>
</ram:ShipToTradeParty>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20181204</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
<ram:DespatchAdviceReferencedDocument>
<ram:IssuerAssignedID>lmn</ram:IssuerAssignedID>
</ram:DespatchAdviceReferencedDocument>
<ram:ReceivingAdviceReferencedDocument>
<ram:IssuerAssignedID>ghi</ram:IssuerAssignedID>
</ram:ReceivingAdviceReferencedDocument>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:CreditorReferenceID>Bank assigned creditor identifier</ram:CreditorReferenceID>
<ram:PaymentReference>Remittance information</ram:PaymentReference>
<ram:TaxCurrencyCode>NOK</ram:TaxCurrencyCode>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:PayeeTradeParty>
<ram:GlobalID schemeID="0098">Payee identifier</ram:GlobalID>
<ram:Name>Payee name</ram:Name>
<ram:SpecifiedLegalOrganization>
<ram:ID schemeID="0099">Payee legal registration identifier</ram:ID>
</ram:SpecifiedLegalOrganization>
</ram:PayeeTradeParty>
<ram:SpecifiedTradeSettlementPaymentMeans>
<ram:TypeCode>4</ram:TypeCode>
<ram:Information>SEPA</ram:Information>
<ram:ApplicableTradeSettlementFinancialCard>
<ram:ID>1234</ram:ID>
<ram:CardholderName>Payment card holder name</ram:CardholderName>
</ram:ApplicableTradeSettlementFinancialCard>
<ram:PayerPartyDebtorFinancialAccount>
<ram:IBANID>Debited account identifier</ram:IBANID>
</ram:PayerPartyDebtorFinancialAccount>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>IT1212341234123412</ram:IBANID>
<ram:AccountName>Payment account name</ram:AccountName>
</ram:PayeePartyCreditorFinancialAccount>
<ram:PayerSpecifiedDebtorFinancialInstitution>
<ram:BICID>BSCTCH22</ram:BICID>
</ram:PayerSpecifiedDebtorFinancialInstitution>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>IT1212341234123413</ram:IBANID>
<ram:AccountName>Payment account name 2</ram:AccountName>
</ram:PayeePartyCreditorFinancialAccount>
<ram:PayerSpecifiedDebtorFinancialInstitution>
<ram:BICID>BSCTCH22</ram:BICID>
</ram:PayerSpecifiedDebtorFinancialInstitution>
</ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>50.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:DueDateTypeCode>29</ram:DueDateTypeCode>
<ram:RateApplicablePercent>5.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>0.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:ExemptionReason>Exemtion reason text</ram:ExemptionReason>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:CategoryCode>E</ram:CategoryCode>
<ram:ExemptionReasonCode>Exemption reason code</ram:ExemptionReasonCode>
<ram:DueDateTypeCode>29</ram:DueDateTypeCode>
<ram:RateApplicablePercent>0.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:BillingSpecifiedPeriod>
<ram:StartDateTime>
<udt:DateTimeString format="102">20181112</udt:DateTimeString>
</ram:StartDateTime>
<ram:EndDateTime>
<udt:DateTimeString format="102">20181130</udt:DateTimeString>
</ram:EndDateTime>
</ram:BillingSpecifiedPeriod>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>55</ram:ReasonCode>
<ram:Reason>Doc allowance reason text</ram:Reason>
<ram:CategoryTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>5.00</ram:RateApplicablePercent>
</ram:CategoryTradeTax>
</ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>true</udt:Indicator>
</ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>AAA</ram:ReasonCode>
<ram:Reason>Doc charge reason text</ram:Reason>
<ram:CategoryTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>5.00</ram:RateApplicablePercent>
</ram:CategoryTradeTax>
</ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>total amount</ram:Description>
<ram:DueDateDateTime>
<udt:DateTimeString format="102">20181130</udt:DateTimeString>
</ram:DueDateDateTime>
<ram:DirectDebitMandateID>Mandate reference identifier</ram:DirectDebitMandateID>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>2000.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>10.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>10.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>2000.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">50.00</ram:TaxTotalAmount>
<ram:TaxTotalAmount currencyID="NOK">46.00</ram:TaxTotalAmount>
<ram:RoundingAmount>0.00</ram:RoundingAmount>
<ram:GrandTotalAmount>2050.00</ram:GrandTotalAmount>
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
<ram:DuePayableAmount>2050.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:InvoiceReferencedDocument>
<ram:IssuerAssignedID>abc123</ram:IssuerAssignedID>
<ram:FormattedIssueDateTime>
<qdt:DateTimeString format="102">20181004</qdt:DateTimeString>
</ram:FormattedIssueDateTime>
</ram:InvoiceReferencedDocument>
<ram:ReceivableSpecifiedTradeAccountingAccount>
<ram:ID>uvz</ram:ID>
</ram:ReceivableSpecifiedTradeAccountingAccount>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</ram:IssueDateTime>
<ram:IncludedNote>
<ram:Content>invoice note text</ram:Content>
<ram:SubjectCode>#AAA#</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>invoice note text 2</ram:Content>
<ram:SubjectCode>#AAA#</ram:SubjectCode>
</ram:IncludedNote>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1a</ram:LineID>
<ram:IncludedNote>
<ram:Content>Invoice line note</ram:Content>
</ram:IncludedNote>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID>Item standar identifier</ram:GlobalID>
<ram:SellerAssignedID>Item seller's identifier</ram:SellerAssignedID>
<ram:BuyerAssignedID>Item buyer's identifier</ram:BuyerAssignedID>
<ram:Name>Item name</ram:Name>
<ram:Description>Item description</ram:Description>
<ram:ApplicableProductCharacteristic>
<ram:Description>Color</ram:Description>
<ram:Value>Red</ram:Value>
</ram:ApplicableProductCharacteristic>
<ram:ApplicableProductCharacteristic>
<ram:Description>Size</ram:Description>
<ram:Value>L</ram:Value>
</ram:ApplicableProductCharacteristic>
<ram:DesignatedProductClassification>
<ram:ClassCode listID="ZZZ" listVersionID="version0">Item classification identifier0</ram:ClassCode>
</ram:DesignatedProductClassification>
<ram:OriginTradeCountry>
<ram:ID>IT</ram:ID>
</ram:OriginTradeCountry>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:BuyerOrderReferencedDocument>
<ram:LineID>12345</ram:LineID>
</ram:BuyerOrderReferencedDocument>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>11.00</ram:ChargeAmount>
<ram:BasisQuantity unitCode="EA">1.00</ram:BasisQuantity>
<ram:AppliedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:ActualAmount>1.00</ram:ActualAmount>
</ram:AppliedTradeAllowanceCharge>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>10.00</ram:ChargeAmount>
<ram:BasisQuantity unitCode="EA">1.00</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="EA">10.00</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>5.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:BillingSpecifiedPeriod>
<ram:StartDateTime>
<udt:DateTimeString format="102">20181112</udt:DateTimeString>
</ram:StartDateTime>
<ram:EndDateTime>
<udt:DateTimeString format="102">20181130</udt:DateTimeString>
</ram:EndDateTime>
</ram:BillingSpecifiedPeriod>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>55</ram:ReasonCode>
<ram:Reason>Invoice line allowance reason</ram:Reason>
</ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>true</udt:Indicator>
</ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>AAA</ram:ReasonCode>
<ram:Reason>Invoice line charge reason</ram:Reason>
</ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>1000.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>Line object identifier</ram:IssuerAssignedID>
<ram:TypeCode>130</ram:TypeCode>
<ram:ReferenceTypeCode />
</ram:AdditionalReferencedDocument>
<ram:ReceivableSpecifiedTradeAccountingAccount>
<ram:ID>6789</ram:ID>
</ram:ReceivableSpecifiedTradeAccountingAccount>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1b</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Item name 2</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>10.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="EA">10.00</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>E</ram:CategoryCode>
<ram:RateApplicablePercent>0.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>1000.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:BuyerReference>123</ram:BuyerReference>
<ram:SellerTradeParty>
<ram:GlobalID schemeID="0100">Seller identifier 1</ram:GlobalID>
<ram:GlobalID schemeID="0110">Seller identifier 2</ram:GlobalID>
<ram:Name>Seller name</ram:Name>
<ram:Description>Seller additional legal information</ram:Description>
<ram:SpecifiedLegalOrganization>
<ram:ID schemeID="0310">Seller legal identifier</ram:ID>
<ram:TradingBusinessName>Seller trading name</ram:TradingBusinessName>
</ram:SpecifiedLegalOrganization>
<ram:DefinedTradeContact>
<ram:PersonName>Seller contact point</ram:PersonName>
<ram:TelephoneUniversalCommunication>
<ram:CompleteNumber>+41 345 654455</ram:CompleteNumber>
</ram:TelephoneUniversalCommunication>
<ram:EmailURIUniversalCommunication>
<ram:URIID>seller@contact.de</ram:URIID>
</ram:EmailURIUniversalCommunication>
</ram:DefinedTradeContact>
<ram:PostalTradeAddress>
<ram:PostcodeCode>12345</ram:PostcodeCode>
<ram:LineOne>Seller address line 1</ram:LineOne>
<ram:LineTwo>Seller address line 2</ram:LineTwo>
<ram:LineThree>Seller address line 3</ram:LineThree>
<ram:CityName>Seller city</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
<ram:CountrySubDivisionName>Seller country subdivision</ram:CountrySubDivisionName>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID schemeID="SMTP">Seller electronic address</ram:URIID>
</ram:URIUniversalCommunication>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE12345677</ram:ID>
</ram:SpecifiedTaxRegistration>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="FC">DE49294093</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:GlobalID schemeID="0190">Buyer identifier</ram:GlobalID>
<ram:Name>Buyer name</ram:Name>
<ram:SpecifiedLegalOrganization>
<ram:ID schemeID="0089">Buyer legal registration identifier</ram:ID>
<ram:TradingBusinessName>Buyer trading name</ram:TradingBusinessName>
</ram:SpecifiedLegalOrganization>
<ram:DefinedTradeContact>
<ram:PersonName>Buyer contact point</ram:PersonName>
<ram:TelephoneUniversalCommunication>
<ram:CompleteNumber>+353 2948584</ram:CompleteNumber>
</ram:TelephoneUniversalCommunication>
<ram:EmailURIUniversalCommunication>
<ram:URIID>buyer@contact.ie</ram:URIID>
</ram:EmailURIUniversalCommunication>
</ram:DefinedTradeContact>
<ram:PostalTradeAddress>
<ram:PostcodeCode>34562</ram:PostcodeCode>
<ram:LineOne>Buyer address line 1</ram:LineOne>
<ram:LineTwo>Buyer address line 2</ram:LineTwo>
<ram:LineThree>Buyer address line 3</ram:LineThree>
<ram:CityName>Buyer city</ram:CityName>
<ram:CountryID>IE</ram:CountryID>
<ram:CountrySubDivisionName>Buyer country subdivision</ram:CountrySubDivisionName>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID schemeID="DE:SMTP">Buyer electronic address</ram:URIID>
</ram:URIUniversalCommunication>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">IE394838894</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
<ram:SellerTaxRepresentativeTradeParty>
<ram:Name>Tax representative name</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>23455</ram:PostcodeCode>
<ram:LineOne>Tax representative address line 1</ram:LineOne>
<ram:LineTwo>Tax representative address line 2</ram:LineTwo>
<ram:LineThree>Tax representative address line 3</ram:LineThree>
<ram:CityName>Tax representative city</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
<ram:CountrySubDivisionName>Tax representative country subdivision</ram:CountrySubDivisionName>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE3949053</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTaxRepresentativeTradeParty>
<ram:SellerOrderReferencedDocument>
<ram:IssuerAssignedID>def</ram:IssuerAssignedID>
</ram:SellerOrderReferencedDocument>
<ram:BuyerOrderReferencedDocument>
<ram:IssuerAssignedID>abc</ram:IssuerAssignedID>
</ram:BuyerOrderReferencedDocument>
<ram:ContractReferencedDocument>
<ram:IssuerAssignedID>789</ram:IssuerAssignedID>
</ram:ContractReferencedDocument>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>Supporting document ref</ram:IssuerAssignedID>
<ram:URIID>External document location</ram:URIID>
<ram:TypeCode>916</ram:TypeCode>
<ram:Name>Supporting document descr</ram:Name>
<ram:AttachmentBinaryObject mimeCode="application/pdf" filename="filename0">ZGVmYXVsdA==</ram:AttachmentBinaryObject>
</ram:AdditionalReferencedDocument>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>rst</ram:IssuerAssignedID>
<ram:TypeCode>130</ram:TypeCode>
<ram:ReferenceTypeCode>0090</ram:ReferenceTypeCode>
</ram:AdditionalReferencedDocument>
<ram:SpecifiedProcuringProject>
<ram:ID>456</ram:ID>
<ram:Name>Project reference</ram:Name>
</ram:SpecifiedProcuringProject>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ShipToTradeParty>
<ram:GlobalID schemeID="0045">deliver location identifier</ram:GlobalID>
<ram:Name>Deliver to party name</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>98765</ram:PostcodeCode>
<ram:LineOne>Deliver to address line 1</ram:LineOne>
<ram:LineTwo>Deliver to address line 2</ram:LineTwo>
<ram:LineThree>Deliver to address line 3</ram:LineThree>
<ram:CityName>Deliver to city</ram:CityName>
<ram:CountryID>IE</ram:CountryID>
<ram:CountrySubDivisionName>Deliver to country subdivision</ram:CountrySubDivisionName>
</ram:PostalTradeAddress>
</ram:ShipToTradeParty>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20181204</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
<ram:DespatchAdviceReferencedDocument>
<ram:IssuerAssignedID>lmn</ram:IssuerAssignedID>
</ram:DespatchAdviceReferencedDocument>
<ram:ReceivingAdviceReferencedDocument>
<ram:IssuerAssignedID>ghi</ram:IssuerAssignedID>
</ram:ReceivingAdviceReferencedDocument>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:CreditorReferenceID>Bank assigned creditor identifier</ram:CreditorReferenceID>
<ram:PaymentReference>Remittance information</ram:PaymentReference>
<ram:TaxCurrencyCode>NOK</ram:TaxCurrencyCode>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:PayeeTradeParty>
<ram:GlobalID schemeID="0098">Payee identifier</ram:GlobalID>
<ram:Name>Payee name</ram:Name>
<ram:SpecifiedLegalOrganization>
<ram:ID schemeID="0099">Payee legal registration identifier</ram:ID>
</ram:SpecifiedLegalOrganization>
</ram:PayeeTradeParty>
<ram:SpecifiedTradeSettlementPaymentMeans>
<ram:TypeCode>4</ram:TypeCode>
<ram:Information>SEPA</ram:Information>
<ram:ApplicableTradeSettlementFinancialCard>
<ram:ID>1234</ram:ID>
<ram:CardholderName>Payment card holder name</ram:CardholderName>
</ram:ApplicableTradeSettlementFinancialCard>
<ram:PayerPartyDebtorFinancialAccount>
<ram:IBANID>Debited account identifier</ram:IBANID>
</ram:PayerPartyDebtorFinancialAccount>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>IT1212341234123412</ram:IBANID>
<ram:AccountName>Payment account name</ram:AccountName>
</ram:PayeePartyCreditorFinancialAccount>
<ram:PayerSpecifiedDebtorFinancialInstitution>
<ram:BICID>BSCTCH22</ram:BICID>
</ram:PayerSpecifiedDebtorFinancialInstitution>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>IT1212341234123413</ram:IBANID>
<ram:AccountName>Payment account name 2</ram:AccountName>
</ram:PayeePartyCreditorFinancialAccount>
<ram:PayerSpecifiedDebtorFinancialInstitution>
<ram:BICID>BSCTCH22</ram:BICID>
</ram:PayerSpecifiedDebtorFinancialInstitution>
</ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>50.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:DueDateTypeCode>29</ram:DueDateTypeCode>
<ram:RateApplicablePercent>5.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>0.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:ExemptionReason>Exemtion reason text</ram:ExemptionReason>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:CategoryCode>E</ram:CategoryCode>
<ram:ExemptionReasonCode>Exemption reason code</ram:ExemptionReasonCode>
<ram:DueDateTypeCode>29</ram:DueDateTypeCode>
<ram:RateApplicablePercent>0.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:BillingSpecifiedPeriod>
<ram:StartDateTime>
<udt:DateTimeString format="102">20181112</udt:DateTimeString>
</ram:StartDateTime>
<ram:EndDateTime>
<udt:DateTimeString format="102">20181130</udt:DateTimeString>
</ram:EndDateTime>
</ram:BillingSpecifiedPeriod>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>55</ram:ReasonCode>
<ram:Reason>Doc allowance reason text</ram:Reason>
<ram:CategoryTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>5.00</ram:RateApplicablePercent>
</ram:CategoryTradeTax>
</ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>true</udt:Indicator>
</ram:ChargeIndicator>
<ram:CalculationPercent>1.00</ram:CalculationPercent>
<ram:BasisAmount>1000.00</ram:BasisAmount>
<ram:ActualAmount>10.00</ram:ActualAmount>
<ram:ReasonCode>AAA</ram:ReasonCode>
<ram:Reason>Doc charge reason text</ram:Reason>
<ram:CategoryTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>5.00</ram:RateApplicablePercent>
</ram:CategoryTradeTax>
</ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>total amount</ram:Description>
<ram:DueDateDateTime>
<udt:DateTimeString format="102">20181130</udt:DateTimeString>
</ram:DueDateDateTime>
<ram:DirectDebitMandateID>Mandate reference identifier</ram:DirectDebitMandateID>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>2000.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>10.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>10.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>2000.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">50.00</ram:TaxTotalAmount>
<ram:TaxTotalAmount currencyID="NOK">46.00</ram:TaxTotalAmount>
<ram:RoundingAmount>0.00</ram:RoundingAmount>
<ram:GrandTotalAmount>2050.00</ram:GrandTotalAmount>
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
<ram:DuePayableAmount>2050.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:InvoiceReferencedDocument>
<ram:IssuerAssignedID>abc123</ram:IssuerAssignedID>
<ram:FormattedIssueDateTime>
<qdt:DateTimeString format="102">20181004</qdt:DateTimeString>
</ram:FormattedIssueDateTime>
</ram:InvoiceReferencedDocument>
<ram:ReceivableSpecifiedTradeAccountingAccount>
<ram:ID>uvz</ram:ID>
</ram:ReceivableSpecifiedTradeAccountingAccount>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>

View File

@@ -1,404 +1,401 @@
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ccts="urn:un:unece:uncefact:documentation:2" xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDataTypes-2" xmlns:udt="urn:oasis:names:specification:ubl:schema:xsd:UnqualifiedDataTypes-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>
<cbc:ProfileID>BT-23 Business Process Type</cbc:ProfileID>
<cbc:ID>Test_EeISI_100</cbc:ID>
<cbc:IssueDate>2018-11-12</cbc:IssueDate>
<cbc:DueDate>2018-11-30</cbc:DueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:Note>##AAA##invoice note text</cbc:Note>
<cbc:Note>##AAA##invoice note text 2</cbc:Note>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cbc:TaxCurrencyCode>NOK</cbc:TaxCurrencyCode>
<cbc:AccountingCost>uvz</cbc:AccountingCost>
<cbc:BuyerReference>123</cbc:BuyerReference>
<cac:InvoicePeriod>
<cbc:StartDate>2018-11-12</cbc:StartDate>
<cbc:EndDate>2018-11-30</cbc:EndDate>
<cbc:DescriptionCode>35</cbc:DescriptionCode>
</cac:InvoicePeriod>
<cac:OrderReference>
<cbc:ID>abc</cbc:ID>
<cbc:SalesOrderID>def</cbc:SalesOrderID>
</cac:OrderReference>
<cac:BillingReference>
<cac:InvoiceDocumentReference>
<cbc:ID>abc123</cbc:ID>
<cbc:IssueDate>2018-10-04</cbc:IssueDate>
</cac:InvoiceDocumentReference>
</cac:BillingReference>
<cac:DespatchDocumentReference>
<cbc:ID>lmn</cbc:ID>
</cac:DespatchDocumentReference>
<cac:ReceiptDocumentReference>
<cbc:ID>ghi</cbc:ID>
</cac:ReceiptDocumentReference>
<cac:OriginatorDocumentReference>
<cbc:ID>opq</cbc:ID>
</cac:OriginatorDocumentReference>
<cac:ContractDocumentReference>
<cbc:ID>789</cbc:ID>
</cac:ContractDocumentReference>
<cac:AdditionalDocumentReference>
<cbc:ID schemeID="0090">rst</cbc:ID>
<cbc:DocumentTypeCode>130</cbc:DocumentTypeCode>
</cac:AdditionalDocumentReference>
<cac:AdditionalDocumentReference>
<cbc:ID>Supporting document ref</cbc:ID>
<cbc:DocumentDescription>Supporting document descr</cbc:DocumentDescription>
<cac:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="application/pdf" filename="filename0">ZGVmYXVsdA==</cbc:EmbeddedDocumentBinaryObject>
<cac:ExternalReference>
<cbc:URI>External document location</cbc:URI>
</cac:ExternalReference>
</cac:Attachment>
</cac:AdditionalDocumentReference>
<cac:ProjectReference>
<cbc:ID>456</cbc:ID>
</cac:ProjectReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="SMTP">Seller electronic address</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID schemeID="0100">Seller identifier 1</cbc:ID>
</cac:PartyIdentification>
<cac:PartyIdentification>
<cbc:ID schemeID="0110">Seller identifier 2</cbc:ID>
</cac:PartyIdentification>
<cac:PartyIdentification>
<cbc:ID schemeID="SEPA">Bank assigned creditor identifier</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Seller trading name</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Seller address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Seller address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Seller city</cbc:CityName>
<cbc:PostalZone>12345</cbc:PostalZone>
<cbc:CountrySubentity>Seller country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Seller address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE12345677</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE49294093</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>NOVAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Seller name</cbc:RegistrationName>
<cbc:CompanyID schemeID="0310">Seller legal identifier</cbc:CompanyID>
<cbc:CompanyLegalForm>Seller additional legal information</cbc:CompanyLegalForm>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>Seller contact point</cbc:Name>
<cbc:Telephone>+41 345 654455</cbc:Telephone>
<cbc:ElectronicMail>seller@contact.de</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="DE:SMTP">Buyer electronic address</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID>0190:Buyer identifier</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Buyer trading name</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Buyer address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Buyer address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Buyer city</cbc:CityName>
<cbc:PostalZone>34562</cbc:PostalZone>
<cbc:CountrySubentity>Buyer country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Buyer address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>IE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>IE394838894</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Buyer name</cbc:RegistrationName>
<cbc:CompanyID>Buyer legal registration identifier</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>Buyer contact point</cbc:Name>
<cbc:Telephone>+353 2948584</cbc:Telephone>
<cbc:ElectronicMail>buyer@contact.ie</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:PayeeParty>
<cac:PartyIdentification>
<cbc:ID schemeID="0098">Payee identifier</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Payee name</cbc:Name>
</cac:PartyName>
<cac:PartyLegalEntity>
<cbc:CompanyID schemeID="0099">Payee legal registration identifier</cbc:CompanyID>
</cac:PartyLegalEntity>
</cac:PayeeParty>
<cac:TaxRepresentativeParty>
<cac:PartyName>
<cbc:Name>Tax representative name</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Tax representative address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Tax representative address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Tax representative city</cbc:CityName>
<cbc:PostalZone>23455</cbc:PostalZone>
<cbc:CountrySubentity>Tax representative country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Tax representative address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE3949053</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
</cac:TaxRepresentativeParty>
<cac:Delivery>
<cbc:ActualDeliveryDate>2018-12-04</cbc:ActualDeliveryDate>
<cac:DeliveryLocation>
<cbc:ID schemeID="0045">deliver location identifier</cbc:ID>
<cac:Address>
<cbc:StreetName>Deliver to address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Deliver to address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Deliver to city</cbc:CityName>
<cbc:PostalZone>98765</cbc:PostalZone>
<cbc:CountrySubentity>Deliver to country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Deliver to address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>IE</cbc:IdentificationCode>
</cac:Country>
</cac:Address>
</cac:DeliveryLocation>
<cac:DeliveryParty>
<cac:PartyName>
<cbc:Name>Deliver to party name</cbc:Name>
</cac:PartyName>
</cac:DeliveryParty>
</cac:Delivery>
<cac:PaymentMeans>
<cbc:PaymentMeansCode name="SEPA">4</cbc:PaymentMeansCode>
<cbc:PaymentID>Remittance information</cbc:PaymentID>
<cac:CardAccount>
<cbc:PrimaryAccountNumberID>1234</cbc:PrimaryAccountNumberID>
<cbc:NetworkID>mandatory network id</cbc:NetworkID>
<cbc:HolderName>Payment card holder name</cbc:HolderName>
</cac:CardAccount>
<cac:PayeeFinancialAccount>
<cbc:ID>IT1212341234123412</cbc:ID>
<cbc:Name>Payment account name</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>BSCTCH22</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
<cac:PayeeFinancialAccount>
<cbc:ID>IT1212341234123413</cbc:ID>
<cbc:Name>Payment account name 2</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>BSCTCH22</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
<cac:PaymentMandate>
<cbc:ID>Mandate reference identifier</cbc:ID>
<cac:PayerFinancialAccount>
<cbc:ID>Debited account identifier</cbc:ID>
</cac:PayerFinancialAccount>
</cac:PaymentMandate>
</cac:PaymentMeans>
<cac:PaymentTerms>
<cbc:Note>total amount</cbc:Note>
</cac:PaymentTerms>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>55</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Doc allowance reason text</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1.0000</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10.00</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000.00</cbc:BaseAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:AllowanceCharge>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>true</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>AAA</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Doc charge reason text</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1.0000</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10.00</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000.00</cbc:BaseAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:AllowanceCharge>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="NOK">46.00</cbc:TaxAmount>
</cac:TaxTotal>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">50.00</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">50.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">0.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>E</cbc:ID>
<cbc:Percent>0.00</cbc:Percent>
<cbc:TaxExemptionReasonCode>Exemption reason code</cbc:TaxExemptionReasonCode>
<cbc:TaxExemptionReason>Exemtion reason text</cbc:TaxExemptionReason>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">2000.00</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">2000.00</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">2050.00</cbc:TaxInclusiveAmount>
<cbc:AllowanceTotalAmount currencyID="EUR">10.00</cbc:AllowanceTotalAmount>
<cbc:ChargeTotalAmount currencyID="EUR">10.00</cbc:ChargeTotalAmount>
<cbc:PayableAmount currencyID="EUR">2050.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1a</cbc:ID>
<cbc:Note>Invoice line note</cbc:Note>
<cbc:InvoicedQuantity unitCode="EA">10.00000000</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount>
<cbc:AccountingCost>6789</cbc:AccountingCost>
<cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>
<cbc:ProfileID>BT-23 Business Process Type</cbc:ProfileID>
<cbc:ID>Test_EeISI_100</cbc:ID>
<cbc:IssueDate>2018-11-12</cbc:IssueDate>
<cbc:DueDate>2018-11-30</cbc:DueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:Note>##AAA##invoice note text</cbc:Note>
<cbc:Note>##AAA##invoice note text 2</cbc:Note>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cbc:TaxCurrencyCode>NOK</cbc:TaxCurrencyCode>
<cbc:AccountingCost>uvz</cbc:AccountingCost>
<cbc:BuyerReference>123</cbc:BuyerReference>
<cac:InvoicePeriod>
<cbc:StartDate>2018-11-12</cbc:StartDate>
<cbc:EndDate>2018-11-30</cbc:EndDate>
<cbc:StartDate>2018-11-12</cbc:StartDate>
<cbc:EndDate>2018-11-30</cbc:EndDate>
<cbc:DescriptionCode>35</cbc:DescriptionCode>
</cac:InvoicePeriod>
<cac:OrderLineReference>
<cbc:LineID>12345</cbc:LineID>
</cac:OrderLineReference>
<cac:DocumentReference>
<cbc:ID schemeID="ZZZ">Line object identifier</cbc:ID>
<cbc:DocumentTypeCode>130</cbc:DocumentTypeCode>
</cac:DocumentReference>
<cac:OrderReference>
<cbc:ID>abc</cbc:ID>
<cbc:SalesOrderID>def</cbc:SalesOrderID>
</cac:OrderReference>
<cac:BillingReference>
<cac:InvoiceDocumentReference>
<cbc:ID>abc123</cbc:ID>
<cbc:IssueDate>2018-10-04</cbc:IssueDate>
</cac:InvoiceDocumentReference>
</cac:BillingReference>
<cac:DespatchDocumentReference>
<cbc:ID>lmn</cbc:ID>
</cac:DespatchDocumentReference>
<cac:ReceiptDocumentReference>
<cbc:ID>ghi</cbc:ID>
</cac:ReceiptDocumentReference>
<cac:OriginatorDocumentReference>
<cbc:ID>opq</cbc:ID>
</cac:OriginatorDocumentReference>
<cac:ContractDocumentReference>
<cbc:ID>789</cbc:ID>
</cac:ContractDocumentReference>
<cac:AdditionalDocumentReference>
<cbc:ID schemeID="0090">rst</cbc:ID>
<cbc:DocumentTypeCode>130</cbc:DocumentTypeCode>
</cac:AdditionalDocumentReference>
<cac:AdditionalDocumentReference>
<cbc:ID>Supporting document ref</cbc:ID>
<cbc:DocumentDescription>Supporting document descr</cbc:DocumentDescription>
<cac:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="application/pdf" filename="filename0">ZGVmYXVsdA==</cbc:EmbeddedDocumentBinaryObject>
<cac:ExternalReference>
<cbc:URI>External document location</cbc:URI>
</cac:ExternalReference>
</cac:Attachment>
</cac:AdditionalDocumentReference>
<cac:ProjectReference>
<cbc:ID>456</cbc:ID>
</cac:ProjectReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="SMTP">Seller electronic address</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID schemeID="0100">Seller identifier 1</cbc:ID>
</cac:PartyIdentification>
<cac:PartyIdentification>
<cbc:ID schemeID="0110">Seller identifier 2</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Seller trading name</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Seller address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Seller address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Seller city</cbc:CityName>
<cbc:PostalZone>12345</cbc:PostalZone>
<cbc:CountrySubentity>Seller country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Seller address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE12345677</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE49294093</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>NOVAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Seller name</cbc:RegistrationName>
<cbc:CompanyID schemeID="0310">Seller legal identifier</cbc:CompanyID>
<cbc:CompanyLegalForm>Seller additional legal information</cbc:CompanyLegalForm>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>Seller contact point</cbc:Name>
<cbc:Telephone>+41 345 654455</cbc:Telephone>
<cbc:ElectronicMail>seller@contact.de</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="DE:SMTP">Buyer electronic address</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID>0190:Buyer identifier</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Buyer trading name</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Buyer address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Buyer address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Buyer city</cbc:CityName>
<cbc:PostalZone>34562</cbc:PostalZone>
<cbc:CountrySubentity>Buyer country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Buyer address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>IE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>IE394838894</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Buyer name</cbc:RegistrationName>
<cbc:CompanyID>Buyer legal registration identifier</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>Buyer contact point</cbc:Name>
<cbc:Telephone>+353 2948584</cbc:Telephone>
<cbc:ElectronicMail>buyer@contact.ie</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:PayeeParty>
<cac:PartyIdentification>
<cbc:ID schemeID="0098">Payee identifier</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Payee name</cbc:Name>
</cac:PartyName>
<cac:PartyLegalEntity>
<cbc:CompanyID schemeID="0099">Payee legal registration identifier</cbc:CompanyID>
</cac:PartyLegalEntity>
</cac:PayeeParty>
<cac:TaxRepresentativeParty>
<cac:PartyName>
<cbc:Name>Tax representative name</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Tax representative address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Tax representative address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Tax representative city</cbc:CityName>
<cbc:PostalZone>23455</cbc:PostalZone>
<cbc:CountrySubentity>Tax representative country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Tax representative address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE3949053</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
</cac:TaxRepresentativeParty>
<cac:Delivery>
<cbc:ActualDeliveryDate>2018-12-04</cbc:ActualDeliveryDate>
<cac:DeliveryLocation>
<cbc:ID schemeID="0045">deliver location identifier</cbc:ID>
<cac:Address>
<cbc:StreetName>Deliver to address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Deliver to address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Deliver to city</cbc:CityName>
<cbc:PostalZone>98765</cbc:PostalZone>
<cbc:CountrySubentity>Deliver to country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Deliver to address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>IE</cbc:IdentificationCode>
</cac:Country>
</cac:Address>
</cac:DeliveryLocation>
<cac:DeliveryParty>
<cac:PartyName>
<cbc:Name>Deliver to party name</cbc:Name>
</cac:PartyName>
</cac:DeliveryParty>
</cac:Delivery>
<cac:PaymentMeans>
<cbc:PaymentMeansCode name="SEPA">4</cbc:PaymentMeansCode>
<cbc:PaymentID>Remittance information</cbc:PaymentID>
<cac:CardAccount>
<cbc:PrimaryAccountNumberID>1234</cbc:PrimaryAccountNumberID>
<cbc:NetworkID>mandatory network id</cbc:NetworkID>
<cbc:HolderName>Payment card holder name</cbc:HolderName>
</cac:CardAccount>
<cac:PayeeFinancialAccount>
<cbc:ID>IT1212341234123412</cbc:ID>
<cbc:Name>Payment account name</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>BSCTCH22</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
<cac:PayeeFinancialAccount>
<cbc:ID>IT1212341234123413</cbc:ID>
<cbc:Name>Payment account name 2</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>BSCTCH22</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
<cac:PaymentMandate>
<cbc:ID>Mandate reference identifier</cbc:ID>
<cac:PayerFinancialAccount>
<cbc:ID>Debited account identifier</cbc:ID>
</cac:PayerFinancialAccount>
</cac:PaymentMandate>
</cac:PaymentMeans>
<cac:PaymentTerms>
<cbc:Note>total amount</cbc:Note>
</cac:PaymentTerms>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>55</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Invoice line allowance reason</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000</cbc:BaseAmount>
</cac:AllowanceCharge>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>true</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>AAA</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Invoice line charge reason</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000</cbc:BaseAmount>
</cac:AllowanceCharge>
<cac:Item>
<cbc:Description>Item description</cbc:Description>
<cbc:Name>Item name</cbc:Name>
<cac:BuyersItemIdentification>
<cbc:ID>Item buyer's identifier</cbc:ID>
</cac:BuyersItemIdentification>
<cac:SellersItemIdentification>
<cbc:ID>Item seller's identifier</cbc:ID>
</cac:SellersItemIdentification>
<cac:StandardItemIdentification>
<cbc:ID>Item standar identifier</cbc:ID>
</cac:StandardItemIdentification>
<cac:OriginCountry>
<cbc:IdentificationCode>IT</cbc:IdentificationCode>
</cac:OriginCountry>
<cac:CommodityClassification>
<cbc:ItemClassificationCode listID="ZZZ" listVersionID="version0">Item classification identifier0</cbc:ItemClassificationCode>
</cac:CommodityClassification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
<cac:AdditionalItemProperty>
<cbc:Name>Color</cbc:Name>
<cbc:Value>Red</cbc:Value>
</cac:AdditionalItemProperty>
<cac:AdditionalItemProperty>
<cbc:Name>Size</cbc:Name>
<cbc:Value>L</cbc:Value>
</cac:AdditionalItemProperty>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">10.00</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="EA">1.00</cbc:BaseQuantity>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:Amount currencyID="EUR">1</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">11</cbc:BaseAmount>
</cac:AllowanceCharge>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>1b</cbc:ID>
<cbc:InvoicedQuantity unitCode="EA">10.00000000</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Item name 2</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>E</cbc:ID>
<cbc:Percent>0.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">10.00</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
<cbc:AllowanceChargeReasonCode>55</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Doc allowance reason text</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1.0000</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10.00</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000.00</cbc:BaseAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:AllowanceCharge>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>true</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>AAA</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Doc charge reason text</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1.0000</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10.00</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000.00</cbc:BaseAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:AllowanceCharge>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="NOK">46.00</cbc:TaxAmount>
</cac:TaxTotal>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">50.00</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">50.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">0.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>E</cbc:ID>
<cbc:Percent>0.00</cbc:Percent>
<cbc:TaxExemptionReasonCode>Exemption reason code</cbc:TaxExemptionReasonCode>
<cbc:TaxExemptionReason>Exemtion reason text</cbc:TaxExemptionReason>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">2000.00</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">2000.00</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">2050.00</cbc:TaxInclusiveAmount>
<cbc:AllowanceTotalAmount currencyID="EUR">10.00</cbc:AllowanceTotalAmount>
<cbc:ChargeTotalAmount currencyID="EUR">10.00</cbc:ChargeTotalAmount>
<cbc:PayableAmount currencyID="EUR">2050.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1a</cbc:ID>
<cbc:Note>Invoice line note</cbc:Note>
<cbc:InvoicedQuantity unitCode="EA">10.00000000</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount>
<cbc:AccountingCost>6789</cbc:AccountingCost>
<cac:InvoicePeriod>
<cbc:StartDate>2018-11-12</cbc:StartDate>
<cbc:EndDate>2018-11-30</cbc:EndDate>
</cac:InvoicePeriod>
<cac:OrderLineReference>
<cbc:LineID>12345</cbc:LineID>
</cac:OrderLineReference>
<cac:DocumentReference>
<cbc:ID schemeID="ZZZ">Line object identifier</cbc:ID>
<cbc:DocumentTypeCode>130</cbc:DocumentTypeCode>
</cac:DocumentReference>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>55</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Invoice line allowance reason</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000</cbc:BaseAmount>
</cac:AllowanceCharge>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>true</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>AAA</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Invoice line charge reason</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>1</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="EUR">10</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">1000</cbc:BaseAmount>
</cac:AllowanceCharge>
<cac:Item>
<cbc:Description>Item description</cbc:Description>
<cbc:Name>Item name</cbc:Name>
<cac:BuyersItemIdentification>
<cbc:ID>Item buyer's identifier</cbc:ID>
</cac:BuyersItemIdentification>
<cac:SellersItemIdentification>
<cbc:ID>Item seller's identifier</cbc:ID>
</cac:SellersItemIdentification>
<cac:StandardItemIdentification>
<cbc:ID>Item standar identifier</cbc:ID>
</cac:StandardItemIdentification>
<cac:OriginCountry>
<cbc:IdentificationCode>IT</cbc:IdentificationCode>
</cac:OriginCountry>
<cac:CommodityClassification>
<cbc:ItemClassificationCode listID="ZZZ" listVersionID="version0">Item classification identifier0</cbc:ItemClassificationCode>
</cac:CommodityClassification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
<cac:AdditionalItemProperty>
<cbc:Name>Color</cbc:Name>
<cbc:Value>Red</cbc:Value>
</cac:AdditionalItemProperty>
<cac:AdditionalItemProperty>
<cbc:Name>Size</cbc:Name>
<cbc:Value>L</cbc:Value>
</cac:AdditionalItemProperty>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">10.00</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="EA">1.00</cbc:BaseQuantity>
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:Amount currencyID="EUR">1</cbc:Amount>
<cbc:BaseAmount currencyID="EUR">11</cbc:BaseAmount>
</cac:AllowanceCharge>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>1b</cbc:ID>
<cbc:InvoicedQuantity unitCode="EA">10.00000000</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Item name 2</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>E</cbc:ID>
<cbc:Percent>0.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">10.00</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
</Invoice>

View File

@@ -1,349 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ccts="urn:un:unece:uncefact:documentation:2" xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDataTypes-2" xmlns:udt="urn:oasis:names:specification:ubl:schema:xsd:UnqualifiedDataTypes-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>
<cbc:ProfileID>BT-23 Business Process Type</cbc:ProfileID>
<cbc:ID>Test_EeISI_100</cbc:ID>
<cbc:IssueDate>2018-11-12</cbc:IssueDate>
<cbc:DueDate>2018-11-30</cbc:DueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:Note>##AAA##invoice note text</cbc:Note>
<cbc:Note>##AAA##invoice note text 2</cbc:Note>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cbc:TaxCurrencyCode>NOK</cbc:TaxCurrencyCode>
<cbc:AccountingCost>uvz</cbc:AccountingCost>
<cbc:BuyerReference>123</cbc:BuyerReference>
<cac:InvoicePeriod>
<cbc:StartDate>2018-11-12</cbc:StartDate>
<cbc:EndDate>2018-11-30</cbc:EndDate>
<cbc:DescriptionCode>35</cbc:DescriptionCode>
</cac:InvoicePeriod>
<cac:OrderReference>
<cbc:ID>abc</cbc:ID>
<cbc:SalesOrderID>def</cbc:SalesOrderID>
</cac:OrderReference>
<cac:BillingReference>
<cac:InvoiceDocumentReference>
<cbc:ID>abc123</cbc:ID>
<cbc:IssueDate>2018-10-04</cbc:IssueDate>
</cac:InvoiceDocumentReference>
</cac:BillingReference>
<cac:DespatchDocumentReference>
<cbc:ID>lmn</cbc:ID>
</cac:DespatchDocumentReference>
<cac:ReceiptDocumentReference>
<cbc:ID>ghi</cbc:ID>
</cac:ReceiptDocumentReference>
<cac:OriginatorDocumentReference>
<cbc:ID>opq</cbc:ID>
</cac:OriginatorDocumentReference>
<cac:ContractDocumentReference>
<cbc:ID>789</cbc:ID>
</cac:ContractDocumentReference>
<cac:AdditionalDocumentReference>
<cbc:ID schemeID="0090">rst</cbc:ID>
<cbc:DocumentTypeCode>130</cbc:DocumentTypeCode>
</cac:AdditionalDocumentReference>
<cac:AdditionalDocumentReference>
<cbc:ID>Supporting document ref</cbc:ID>
<cbc:DocumentDescription>Supporting document descr</cbc:DocumentDescription>
<cac:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="application/pdf" filename="filename0">ZGVmYXVsdA==</cbc:EmbeddedDocumentBinaryObject>
<cac:ExternalReference>
<cbc:URI>External document location</cbc:URI>
</cac:ExternalReference>
</cac:Attachment>
</cac:AdditionalDocumentReference>
<cac:ProjectReference>
<cbc:ID>456</cbc:ID>
</cac:ProjectReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="SMTP">Seller electronic address</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID schemeID="0100">Seller identifier 1</cbc:ID>
</cac:PartyIdentification>
<cac:PartyIdentification>
<cbc:ID schemeID="0110">Seller identifier 2</cbc:ID>
</cac:PartyIdentification>
<cac:PartyIdentification>
<cbc:ID schemeID="SEPA">Bank assigned creditor identifier</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Seller trading name</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Seller address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Seller address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Seller city</cbc:CityName>
<cbc:PostalZone>12345</cbc:PostalZone>
<cbc:CountrySubentity>Seller country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Seller address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE12345677</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE49294093</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>NOVAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Seller name</cbc:RegistrationName>
<cbc:CompanyID schemeID="0310">Seller legal identifier</cbc:CompanyID>
<cbc:CompanyLegalForm>Seller additional legal information</cbc:CompanyLegalForm>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>Seller contact point</cbc:Name>
<cbc:Telephone>+41 345 654455</cbc:Telephone>
<cbc:ElectronicMail>seller@contact.de</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="DE:SMTP">Buyer electronic address</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID>0190:Buyer identifier</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Buyer trading name</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Buyer address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Buyer address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Buyer city</cbc:CityName>
<cbc:PostalZone>34562</cbc:PostalZone>
<cbc:CountrySubentity>Buyer country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Buyer address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>IE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>IE394838894</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Buyer name</cbc:RegistrationName>
<cbc:CompanyID>Buyer legal registration identifier</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>Buyer contact point</cbc:Name>
<cbc:Telephone>+353 2948584</cbc:Telephone>
<cbc:ElectronicMail>buyer@contact.ie</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:PayeeParty>
<cac:PartyIdentification>
<cbc:ID schemeID="0098">Payee identifier</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>Payee name</cbc:Name>
</cac:PartyName>
<cac:PartyLegalEntity>
<cbc:CompanyID schemeID="0099">Payee legal registration identifier</cbc:CompanyID>
</cac:PartyLegalEntity>
</cac:PayeeParty>
<cac:TaxRepresentativeParty>
<cac:PartyName>
<cbc:Name>Tax representative name</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Tax representative address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Tax representative address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Tax representative city</cbc:CityName>
<cbc:PostalZone>23455</cbc:PostalZone>
<cbc:CountrySubentity>Tax representative country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Tax representative address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE3949053</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
</cac:TaxRepresentativeParty>
<cac:Delivery>
<cbc:ActualDeliveryDate>2018-12-04</cbc:ActualDeliveryDate>
<cac:DeliveryLocation>
<cbc:ID schemeID="0045">deliver location identifier</cbc:ID>
<cac:Address>
<cbc:StreetName>Deliver to address line 1</cbc:StreetName>
<cbc:AdditionalStreetName>Deliver to address line 2</cbc:AdditionalStreetName>
<cbc:CityName>Deliver to city</cbc:CityName>
<cbc:PostalZone>98765</cbc:PostalZone>
<cbc:CountrySubentity>Deliver to country subdivision</cbc:CountrySubentity>
<cac:AddressLine>
<cbc:Line>Deliver to address line 3</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>IE</cbc:IdentificationCode>
</cac:Country>
</cac:Address>
</cac:DeliveryLocation>
<cac:DeliveryParty>
<cac:PartyName>
<cbc:Name>Deliver to party name</cbc:Name>
</cac:PartyName>
</cac:DeliveryParty>
</cac:Delivery>
<cac:PaymentMeans>
<cbc:PaymentMeansCode name="SEPA">4</cbc:PaymentMeansCode>
<cbc:PaymentID>Remittance information</cbc:PaymentID>
<cac:CardAccount>
<cbc:PrimaryAccountNumberID>1234</cbc:PrimaryAccountNumberID>
<cbc:NetworkID>mandatory network id</cbc:NetworkID>
<cbc:HolderName>Payment card holder name</cbc:HolderName>
</cac:CardAccount>
<cac:PayeeFinancialAccount>
<cbc:ID>IT1212341234123412</cbc:ID>
<cbc:Name>Payment account name</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>BSCTCH22</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
<cac:PayeeFinancialAccount>
<cbc:ID>IT1212341234123413</cbc:ID>
<cbc:Name>Payment account name 2</cbc:Name>
<cac:FinancialInstitutionBranch>
<cbc:ID>BSCTCH22</cbc:ID>
</cac:FinancialInstitutionBranch>
</cac:PayeeFinancialAccount>
<cac:PaymentMandate>
<cbc:ID>Mandate reference identifier</cbc:ID>
<cac:PayerFinancialAccount>
<cbc:ID>Debited account identifier</cbc:ID>
</cac:PayerFinancialAccount>
</cac:PaymentMandate>
</cac:PaymentMeans>
<cac:PaymentTerms>
<cbc:Note>total amount</cbc:Note>
</cac:PaymentTerms>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">50.00</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">50.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">1000.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">0.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>E</cbc:ID>
<cbc:Percent>0.00</cbc:Percent>
<cbc:TaxExemptionReasonCode>Exemption reason code</cbc:TaxExemptionReasonCode>
<cbc:TaxExemptionReason>Exemtion reason text</cbc:TaxExemptionReason>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">200.00</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">200.00</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">205.00</cbc:TaxInclusiveAmount>
<cbc:PayableAmount currencyID="EUR">205.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1a</cbc:ID>
<cbc:Note>Invoice line note</cbc:Note>
<cbc:InvoicedQuantity unitCode="EA">10.00000000</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount>
<cbc:AccountingCost>6789</cbc:AccountingCost>
<cac:InvoicePeriod>
<cbc:StartDate>2018-11-12</cbc:StartDate>
<cbc:EndDate>2018-11-30</cbc:EndDate>
</cac:InvoicePeriod>
<cac:OrderLineReference>
<cbc:LineID>12345</cbc:LineID>
</cac:OrderLineReference>
<cac:DocumentReference>
<cbc:ID schemeID="ZZZ">Line object identifier</cbc:ID>
<cbc:DocumentTypeCode>130</cbc:DocumentTypeCode>
</cac:DocumentReference>
<cac:Item>
<cbc:Description>Item description</cbc:Description>
<cbc:Name>Item name</cbc:Name>
<cac:BuyersItemIdentification>
<cbc:ID>Item buyer's identifier</cbc:ID>
</cac:BuyersItemIdentification>
<cac:SellersItemIdentification>
<cbc:ID>Item seller's identifier</cbc:ID>
</cac:SellersItemIdentification>
<cac:StandardItemIdentification>
<cbc:ID>Item standar identifier</cbc:ID>
</cac:StandardItemIdentification>
<cac:OriginCountry>
<cbc:IdentificationCode>IT</cbc:IdentificationCode>
</cac:OriginCountry>
<cac:CommodityClassification>
<cbc:ItemClassificationCode listID="ZZZ" listVersionID="version0">Item classification identifier0</cbc:ItemClassificationCode>
</cac:CommodityClassification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>5.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
<cac:AdditionalItemProperty>
<cbc:Name>Color</cbc:Name>
<cbc:Value>Red</cbc:Value>
</cac:AdditionalItemProperty>
<cac:AdditionalItemProperty>
<cbc:Name>Size</cbc:Name>
<cbc:Value>L</cbc:Value>
</cac:AdditionalItemProperty>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">10.00</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="EA">1.00</cbc:BaseQuantity>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>1b</cbc:ID>
<cbc:InvoicedQuantity unitCode="EA">10.00000000</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">100.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Item name 2</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>E</cbc:ID>
<cbc:Percent>0.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">10.00</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
</Invoice>

View File

@@ -123,6 +123,7 @@
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:Note>Something</cbc:Note>
<cbc:InvoicedQuantity unitCode="HUR">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">160</cbc:LineExtensionAmount>
<cac:Item>
@@ -178,4 +179,4 @@
<cbc:BaseQuantity unitCode="LTR">1</cbc:BaseQuantity>
</cac:Price>
</cac:InvoiceLine>
</Invoice>
</Invoice>

View File

@@ -3,8 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.15.0-SNAPSHOT</version>
<packaging>pom</packaging>
<version>2.15.3-SNAPSHOT</version> <packaging>pom</packaging>
<name>Mustang</name>
<modules>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.15.0-SNAPSHOT</version>
<version>2.15.3-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.15.0-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
<repositories>
<repository>
<!-- for jargs -->
@@ -38,12 +38,18 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>library</artifactId>
<version>2.15.0-SNAPSHOT</version>
<version>2.15.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.4</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-io</groupId>
@@ -54,7 +60,6 @@
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
@@ -225,10 +230,10 @@
</goals>
<configuration>
<outputDirectory>${basedir}/src/main/resources/xslt/ZF_230/</outputDirectory>
<outputDirectory>src/main/resources/xslt/ZF_232/</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/resources/schematron/ZF_230/</directory>
<directory>${basedir}/src/main/resources/schematron/ZF_232/</directory>
<includes>
<include>**/*.xml</include>
</includes>

View File

@@ -52,7 +52,7 @@ public class PDFValidator extends Validator {
}
private static final Logger LOGGER = LoggerFactory.getLogger(PDFValidator.class.getCanonicalName()); // log output
private static final PDFAFlavour[] PDF_A_3_FLAVOURS = {PDFAFlavour.PDFA_3_A, PDFAFlavour.PDFA_3_A, PDFAFlavour.PDFA_3_A};
private static final PDFAFlavour[] PDF_A_3_FLAVOURS = {PDFAFlavour.PDFA_3_A, PDFAFlavour.PDFA_3_B, PDFAFlavour.PDFA_3_U};
private String pdfFilename;
@@ -122,7 +122,9 @@ public class PDFValidator extends Validator {
}
// step 2 validate XMP
final ZUGFeRDImporter zi = new ZUGFeRDImporter(inputStream);
final ZUGFeRDImporter zi = new ZUGFeRDImporter();
zi.doIgnoreCalculationErrors();//of course the calculation will still be schematron checked
zi.setInputStream(inputStream);
final String xmp = zi.getXMP();
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
@@ -239,7 +241,8 @@ public class PDFValidator extends Validator {
boolean versionValid = false;
for (int i = 0; i < nodes.getLength(); i++) {
final String[] valueArray = {"1.0", "2p0", "1.2", "2.0", "2.1"}; //1.2, 2.0 and 2.1 are for xrechnung 1.2, 2p0 can be ZF 2.0, 2.1, 2.1.1
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
@@ -263,6 +266,8 @@ public class PDFValidator extends Validator {
final byte[] konikSignature = "Konik".getBytes(StandardCharsets.UTF_8);
final byte[] pdfMachineSignature = "pdfMachine from Broadgun Software".getBytes(StandardCharsets.UTF_8);
final byte[] ghostscriptSignature = "%%Invocation:".getBytes(StandardCharsets.UTF_8);
final byte[] cibpdfbrewerSignature = "CIB pdf brewer".getBytes(StandardCharsets.UTF_8);
final byte[] lexofficeSignature = "lexoffice".getBytes(StandardCharsets.UTF_8);
if (ByteArraySearcher.contains(fileContents, symtraxSignature)) {
Signature = "Symtrax";
@@ -278,6 +283,10 @@ public class PDFValidator extends Validator {
Signature = "pdfMachine";
} else if (ByteArraySearcher.contains(fileContents, ghostscriptSignature)) {
Signature = "Ghostscript";
} else if (ByteArraySearcher.contains(fileContents, cibpdfbrewerSignature)) {
Signature = "CIB pdf brewer";
} else if (ByteArraySearcher.contains(fileContents, lexofficeSignature)) {
Signature = "Lexware office";
}
context.setSignature(Signature);
@@ -297,8 +306,10 @@ public class PDFValidator extends Validator {
if (!processorResult.getValidationResult().isCompliant()) {
context.setInvalid();
}
PDFAFlavour pdfaFlavourFromValidationResult = processorResult.getValidationResult().getPDFAFlavour();
if (Arrays.stream(PDF_A_3_FLAVOURS)
.anyMatch(pdfaFlavour -> processorResult.getValidationResult().getPDFAFlavour().equals(pdfaFlavour))) {
.noneMatch(pdfaFlavourFromValidationResult::equals)) {
context.addResultItem(
new ValidationResultItem(ESeverity.error, "Not a PDF/A-3").setSection(23).setPart(EPart.pdf));

View File

@@ -135,6 +135,22 @@ public class ValidationContext {
return String.join(",", errorcodes);
}
/***
*
* @return the unique error IDs as comma separated string
*/
public String getCSVIDResult() {
final ArrayList<String> errorIDs = new ArrayList<>();
for (final ValidationResultItem validationResultItem : results) {
if (!validationResultItem.getID().isEmpty()) {
final String errorID=validationResultItem.getID();
errorIDs.add(errorID);
}
}
return String.join(",", errorIDs);
}
public void setInvalid() {
isValid = false;
}

View File

@@ -12,6 +12,7 @@ public class ValidationResultItem {
protected String message, location=null;
protected int section =-1;
protected String id =""; // e.g. "FX-SCH-A-000026"
private ESeverity severity=ESeverity.error;
@@ -103,6 +104,15 @@ public class ValidationResultItem {
return severity;
}
public ValidationResultItem setID(String id) {
this.id=id;
return this;
}
public String getID() {
return id;
}
public int getSection() {
return section;
}

View File

@@ -1,4 +1,5 @@
package org.mustangproject.validator;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
@@ -69,15 +70,13 @@ public class XMLValidator extends Validator {
final ValidationResultItem vri = new ValidationResultItem(ESeverity.exception, e.getMessage()).setSection(9)
.setPart(EPart.fx);
try (final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw))
{
e.printStackTrace(pw);
vri.setStacktrace(sw.toString());
context.addResultItem(vri);
final PrintWriter pw = new PrintWriter(sw)) {
e.printStackTrace(pw);
vri.setStacktrace(sw.toString());
context.addResultItem(vri);
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
catch (IOException ex) {
throw new UncheckedIOException (ex);
}
}
}
@@ -125,9 +124,9 @@ public class XMLValidator extends Validator {
if (zfXML.isEmpty()) {
final ValidationResultItem res = new ValidationResultItem(ESeverity.exception,
"XML data not found in " + filename
+ ": did you specify a pdf or xml file and does the xml file contain an embedded XML file?")
.setSection(3);
"XML data not found in " + filename
+ ": did you specify a pdf or xml file and does the xml file contain an embedded XML file?")
.setSection(3);
context.addResultItem(res);
} else {
@@ -170,7 +169,7 @@ public class XMLValidator extends Validator {
// Create XPath object
final XPath xpath = xpathFactory.newXPath();
final XPathExpression expr = xpath.compile(
"(//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/*[local-name()=\"ID\"])/text()|//*[local-name()=\"CustomizationID\"]/text()");
"(//*[local-name()=\"GuidelineSpecifiedDocumentContextParameter\"]/*[local-name()=\"ID\"])/text()|//*[local-name()=\"CustomizationID\"]/text()");
// evaluate expression result on XML document
ndList = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
@@ -190,8 +189,8 @@ public class XMLValidator extends Validator {
boolean isEN16931 = false;
boolean isExtended = false;
boolean isXRechnung = false;
String currentZFVersionDir = "ZF_230";
int mainSchematronSectionErrorTypeCode=4;
String currentZFVersionDir = "ZF_232";
int mainSchematronSectionErrorTypeCode = 4;
String xsltFilename = null;
// urn:ferd:CrossIndustryDocument:invoice:1p0:extended,
// urn:ferd:CrossIndustryDocument:invoice:1p0:comfort,
@@ -224,7 +223,7 @@ public class XMLValidator extends Validator {
isBasic = false;// basicwl also contains the string basic...
}
isEN16931 = matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931")
|| matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017");
|| matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017");
isExtended = context.getProfile().contains("extended");
isXRechnung = context.getProfile().contains("xrechnung");
@@ -269,16 +268,16 @@ public class XMLValidator extends Validator {
// saxon java net.sf.saxon.Transform -o tcdl2.0.tsdtf.sch.tmp.xsl -s
// tcdl2.0.tsdtf.sch iso_svrl.xsl
} else if (root.getLocalName().equalsIgnoreCase("Invoice")) {
} else if (root.getLocalName().equalsIgnoreCase("Invoice") || root.getLocalName().equalsIgnoreCase("CreditNote")) {
context.setGeneration("2");
context.setFormat("UBL");
isXRechnung = context.getProfile().contains("xrechnung");
// UBL
LOGGER.debug("UBL");
validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "UBL_21/maindoc/UBL-Invoice-2.1.xsd", 18, EPart.fx);
validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "UBL_21/maindoc/UBL-" + root.getLocalName() + "-2.1.xsd", 18, EPart.fx);
xsltFilename = "/xslt/en16931schematron/EN16931-UBL-validation.xslt";
mainSchematronSectionErrorTypeCode=24;
mainSchematronSectionErrorTypeCode = 24;
if (isXRechnung) {
validateSchematron(zfXML, xsltFilename, 24, ESeverity.error);
@@ -287,14 +286,14 @@ public class XMLValidator extends Validator {
XRechnung is a EN16931 subset so the validation vis a vis FACTUR-X_EN16931.xslt=schematron also has to pass
* */
//validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "ZF_211/EN16931/FACTUR-X_EN16931.xsd", 18, EPart.fx);
String xrVersion=context.getProfile().substring(context.getProfile().length()-3).replace(".","");
if (!xrVersion.equals("12")&&!xrVersion.equals("20")&&!xrVersion.equals("21")&&!xrVersion.equals("22")&&!xrVersion.equals("23")&&!xrVersion.equals("30")) {
String xrVersion = context.getProfile().substring(context.getProfile().length() - 3).replace(".", "");
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);
xsltFilename = "/xslt/XR_"+xrVersion+"/XRechnung-UBL-validation.xslt";
LOGGER.debug("is XRechnung v" + xrVersion);
xsltFilename = "/xslt/XR_" + xrVersion + "/XRechnung-UBL-validation.xslt";
XrechnungSeverity = ESeverity.error;
mainSchematronSectionErrorTypeCode=27;
mainSchematronSectionErrorTypeCode = 27;
}
@@ -302,58 +301,58 @@ public class XMLValidator extends Validator {
context.setGeneration("1");
//
if ((!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort"))
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"))) {
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort"))
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"))) {
context.addResultItem(new ValidationResultItem(ESeverity.error, "Unsupported profile type")
.setSection(25).setPart(EPart.fx));
.setSection(25).setPart(EPart.fx));
}
validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "ZF_10/ZUGFeRD1p0.xsd", 18, EPart.fx);
xsltFilename = "/xslt/ZUGFeRD_1p0.xslt";
} else { // unknown document root
context.addResultItem(new ValidationResultItem(ESeverity.fatal, "Unsupported root element")
.setSection(3).setPart(EPart.fx));
.setSection(3).setPart(EPart.fx));
}
if (context.getFormat().equals("CII")) {
if (context.getGeneration().equals("2")) {
if ((!matchesURI(context.getProfile(), "urn:factur-x.eu:1p0:minimum"))
&& (!matchesURI(context.getProfile(), "urn:zugferd.de:2p0:minimum"))
&& (!matchesURI(context.getProfile(), "urn:factur-x.eu:1p0:basicwl"))
&& (!matchesURI(context.getProfile(), "urn:zugferd.de:2p0:basicwl"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended"))) {
&& (!matchesURI(context.getProfile(), "urn:zugferd.de:2p0:minimum"))
&& (!matchesURI(context.getProfile(), "urn:factur-x.eu:1p0:basicwl"))
&& (!matchesURI(context.getProfile(), "urn:zugferd.de:2p0:basicwl"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended"))
&& (!matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended"))) {
context.addResultItem(
new ValidationResultItem(ESeverity.error, "Unsupported profile type " + context.getProfile())
.setSection(25).setPart(EPart.fx));
new ValidationResultItem(ESeverity.error, "Unsupported profile type " + context.getProfile())
.setSection(25).setPart(EPart.fx));
}
} else /** v1 */ {
if (isOrderX) {
//order-x 1.0
if ((!matchesURI(context.getProfile(), "urn:order-x.eu:1p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:order-x.eu:1p0:comfort"))
&& (!matchesURI(context.getProfile(), "urn:order-x.eu:1p0:extended"))) {
&& (!matchesURI(context.getProfile(), "urn:order-x.eu:1p0:comfort"))
&& (!matchesURI(context.getProfile(), "urn:order-x.eu:1p0:extended"))) {
//zf 1.0
context.addResultItem(new ValidationResultItem(ESeverity.error, "Unsupported profile type")
.setSection(25).setPart(EPart.fx));
.setSection(25).setPart(EPart.fx));
}
} else if ((!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:basic"))
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort"))
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"))) {
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort"))
&& (!matchesURI(context.getProfile(), "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"))) {
//zf 1.0
context.addResultItem(new ValidationResultItem(ESeverity.error, "Unsupported profile type")
.setSection(25).setPart(EPart.fx));
.setSection(25).setPart(EPart.fx));
}
}
}
if (xsltFilename!=null) {
if (xsltFilename != null) {
// main schematron validation
validateSchematron(zfXML, xsltFilename, mainSchematronSectionErrorTypeCode, ESeverity.error);
@@ -362,7 +361,7 @@ public class XMLValidator extends Validator {
if (context.getFormat().equals("CII")) {
if (context.getGeneration().equals("2")
&& (isBasic || isEN16931 || isXRechnung)) {
&& (isBasic || isEN16931 || isXRechnung)) {
//additionally validate against CEN
validateSchematron(zfXML, "/xslt/en16931schematron/EN16931-CII-validation.xslt", 24, ESeverity.error);
if (!disableNotices || XrechnungSeverity != ESeverity.notice) {
@@ -376,7 +375,7 @@ public class XMLValidator extends Validator {
throw er;
} catch (final Exception e) {
final ValidationResultItem vri = new ValidationResultItem(ESeverity.exception, e.getMessage()).setSection(22)
.setPart(EPart.fx);
.setPart(EPart.fx);
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
@@ -388,8 +387,8 @@ public class XMLValidator extends Validator {
final long endTime = Calendar.getInstance().getTimeInMillis();
context.addCustomXML("<info><version>" + ((context.getGeneration() != null) ? context.getGeneration() : "invalid")
+ "</version><profile>" + ((context.getProfile() != null) ? context.getProfile() : "invalid") +
"</profile><validator version=\"" + XMLValidator.class.getPackage().getImplementationVersion() + "\"></validator><rules><fired>" + firedRules + "</fired><failed>" + failedRules + "</failed></rules>" + "<duration unit=\"ms\">" + (endTime - startXMLTime) + "</duration></info>");
+ "</version><profile>" + ((context.getProfile() != null) ? context.getProfile() : "invalid") +
"</profile><validator version=\"" + XMLValidator.class.getPackage().getImplementationVersion() + "\"></validator><rules><fired>" + firedRules + "</fired><failed>" + failedRules + "</failed></rules>" + "<duration unit=\"ms\">" + (endTime - startXMLTime) + "</duration></info>");
}
@@ -419,10 +418,10 @@ public class XMLValidator extends Validator {
* @param xml the xml to be checked
* @param xsltFilename the filename of the intermediate XSLT file
* @param section the error type code, if one arises
* @param severity how serious a error should be treated - may only be notice
* @param defaultSeverity how serious a error should be treated - may only be notice
* @throws IrrecoverableValidationError if anything happened that prevents further checks
*/
public void validateSchematron(String xml, String xsltFilename, int section, ESeverity severity) throws IrrecoverableValidationError {
public void validateSchematron(String xml, String xsltFilename, int section, ESeverity defaultSeverity) throws IrrecoverableValidationError {
ISchematronResource aResSCH = null;
aResSCH = SchematronResourceXSLT.fromClassPath(xsltFilename);
@@ -434,7 +433,7 @@ public class XMLValidator extends Validator {
final SchematronOutputType sout;
try {
sout = aResSCH
.applySchematronValidationToSVRL(new StreamSource(new StringReader(xml)));
.applySchematronValidationToSVRL(new StreamSource(new StringReader(xml)));
} catch (final Exception e) {
throw new IrrecoverableValidationError(e.getMessage());
}
@@ -448,6 +447,7 @@ public class XMLValidator extends Validator {
String thisFailText = "";
String thisFailID = "";
String thisFailIDStr = "";
String thisFailTest = "";
String thisFailLocation = "";
if (failedAsserts.getLength() > 0) {
@@ -456,7 +456,8 @@ public class XMLValidator extends Validator {
//nodes.item(i).getTextContent())) {
Node currentFailNode = failedAsserts.item(nodeIndex);
if (currentFailNode.getAttributes().getNamedItem("id") != null) {
thisFailID = " [ID " + currentFailNode.getAttributes().getNamedItem("id").getNodeValue() + "]";
thisFailID = currentFailNode.getAttributes().getNamedItem("id").getNodeValue();
thisFailIDStr = " [ID " + thisFailID + "]";
}
if (currentFailNode.getAttributes().getNamedItem("test") != null) {
thisFailTest = currentFailNode.getAttributes().getNamedItem("test").getNodeValue();
@@ -465,6 +466,17 @@ public class XMLValidator extends Validator {
thisFailLocation = currentFailNode.getAttributes().getNamedItem("location").getNodeValue();
}
ESeverity severity;
if (defaultSeverity == ESeverity.notice) {
severity = defaultSeverity;
} else if (currentFailNode.getAttributes().getNamedItem("flag") != null
&& currentFailNode.getAttributes().getNamedItem("flag").getNodeValue().equals("warning")) {
// the XR issues warnings with flag=warning
severity = ESeverity.warning;
} else {
severity = ESeverity.error;
}
NodeList failChilds = currentFailNode.getChildNodes();
for (int failChildIndex = 0; failChildIndex < failChilds.getLength(); failChildIndex++) {
if (failChilds.item(failChildIndex).getLocalName() != null) {
@@ -479,9 +491,9 @@ public class XMLValidator extends Validator {
LOGGER.info("FailedAssert ", thisFailText);
context.addResultItem(new ValidationResultItem(severity, thisFailText + thisFailID + " from " + xsltFilename + ")")
.setLocation(thisFailLocation).setCriterion(thisFailTest).setSection(section)
.setPart(EPart.fx));
context.addResultItem(new ValidationResultItem(severity, thisFailText + thisFailIDStr + " from " + xsltFilename + ")")
.setLocation(thisFailLocation).setCriterion(thisFailTest).setSection(section).setID(thisFailID)
.setPart(EPart.fx));
failedRules++;
}
@@ -512,7 +524,7 @@ public class XMLValidator extends Validator {
if (firedRules == 0) {
context.addResultItem(new ValidationResultItem(ESeverity.error, "No rules matched, XML to minimal?").setSection(26)
.setPart(EPart.fx));
.setPart(EPart.fx));
}
// for (String currentString : sout.getText()) {

View File

@@ -318,7 +318,7 @@ public class ZUGFeRDValidator {
LOGGER.info("Parsed PDF:" + pdfResult + " XML:" + (xmlValidity ? "valid" : "invalid")
+ " Signature:" + Signature + " Checksum:" + sha1Checksum + " Profile:" + context.getProfile()
+ " Version:" + context.getGeneration() + " Took:" + duration + "ms Errors:[" + context.getCSVResult()
+ "] " + toBeAppended);
+ "] ErrorIDs: [" + context.getCSVIDResult() + "]" + toBeAppended);
wasCompletelyValid = ((pdfValidity) && (xmlValidity));
return sw.toString();
}

View File

@@ -5,8 +5,8 @@
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
targetNamespace="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
elementFormDefault="qualified">
<xs:import namespace="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" schemaLocation="Factur-X_1.0.07_BASICWL_urn_un_unece_uncefact_data_standard_QualifiedDataType_100.xsd"/>
<xs:import namespace="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" schemaLocation="Factur-X_1.0.07_BASICWL_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_100.xsd"/>
<xs:import namespace="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" schemaLocation="Factur-X_1.07.2_BASICWL_urn_un_unece_uncefact_data_standard_QualifiedDataType_100.xsd"/>
<xs:import namespace="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" schemaLocation="Factur-X_1.07.2_BASICWL_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_100.xsd"/>
<xs:complexType name="CreditorFinancialAccountType">
<xs:sequence>
<xs:element name="IBANID" type="udt:IDType" minOccurs="0"/>

View File

@@ -5,8 +5,8 @@
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
targetNamespace="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
elementFormDefault="qualified">
<xs:import namespace="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" schemaLocation="Factur-X_1.0.07_BASIC_urn_un_unece_uncefact_data_standard_QualifiedDataType_100.xsd"/>
<xs:import namespace="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" schemaLocation="Factur-X_1.0.07_BASIC_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_100.xsd"/>
<xs:import namespace="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" schemaLocation="Factur-X_1.07.2_BASIC_urn_un_unece_uncefact_data_standard_QualifiedDataType_100.xsd"/>
<xs:import namespace="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" schemaLocation="Factur-X_1.07.2_BASIC_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_100.xsd"/>
<xs:complexType name="CreditorFinancialAccountType">
<xs:sequence>
<xs:element name="IBANID" type="udt:IDType" minOccurs="0"/>

Some files were not shown because too many files have changed in this diff Show More