Compare commits

1 Commits

Author SHA1 Message Date
Jochen Stärk
833961a42b test for #1133
Some checks failed
Java CI with Maven / build (push) Has been cancelled
2026-05-29 19:18:06 +02:00
21 changed files with 542 additions and 74 deletions

View File

@@ -1,22 +0,0 @@
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
# For setup-java see: https://github.com/actions/setup-java#Usage
name: Java CI with Maven
on: [push, pull_request]
jobs:
build:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v3 # the log states the default ~/.m2/toolchains.xml is being created pointing to the JDK
with:
distribution: 'adopt' # for latest JDKs use temurin https://blog.adoptopenjdk.net/2021/08/goodbye-adoptopenjdk-hello-adoptium/
java-version: '11'
cache: 'maven' #cache/restore any dependencies to improve the workflow execution time
- name: Build with Maven
run: mvn -B package --file pom.xml

View File

@@ -44,7 +44,7 @@
<github.global.server>github</github.global.server> <github.global.server>github</github.global.server>
<additionalparam>-Xdoclint:none</additionalparam> <additionalparam>-Xdoclint:none</additionalparam>
<!-- Skip error check for javadoc --> <!-- Skip error check for javadoc -->
<maven.compiler.release>8</maven.compiler.release> <maven.compiler.release>11</maven.compiler.release>
<maven.deploy.skip>true</maven.deploy.skip><!-- do deploy to maven central, parent project does not and inherits --> <maven.deploy.skip>true</maven.deploy.skip><!-- do deploy to maven central, parent project does not and inherits -->
</properties> </properties>
<dependencies> <dependencies>
@@ -169,8 +169,8 @@
<!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven <!-- http://stackoverflow.com/questions/574594/how-can-i-create-an-executable-jar-with-dependencies-using-maven
mvn clean compile assembly:single --> mvn clean compile assembly:single -->
<!-- or whatever version you use --> <!-- or whatever version you use -->
<source>8</source> <source>11</source>
<target>8</target> <target>11</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
@@ -331,7 +331,7 @@
<configuration> <configuration>
<toolchains> <toolchains>
<jdk> <jdk>
<version>8</version> <version>11</version>
<vendor>adopt</vendor> <vendor>adopt</vendor>
</jdk> </jdk>
</toolchains> </toolchains>

View File

@@ -5,9 +5,6 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact; import org.mustangproject.ZUGFeRD.IZUGFeRDExportableContact;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
/*** /***
@@ -118,7 +115,7 @@ public class Contact implements IZUGFeRDExportableContact {
String localName = currentItemNode.getLocalName(); String localName = currentItemNode.getLocalName();
if (localName != null) { if (localName != null) {
Set<String> nameElements = new HashSet<>(Arrays.asList("PersonName"/*CII*/, "Name"/*UBL*/)); Set<String> nameElements = Set.of("PersonName"/*CII*/, "Name"/*UBL*/);
if (localName != null && nameElements.contains(localName) if (localName != null && nameElements.contains(localName)
&& currentItemNode.getFirstChild()!=null) { && currentItemNode.getFirstChild()!=null) {
setName(currentItemNode.getFirstChild().getNodeValue()); setName(currentItemNode.getFirstChild().getNodeValue());

View File

@@ -335,7 +335,7 @@ public class Item implements IZUGFeRDExportableItem {
return this; return this;
} }
@Deprecated() @Deprecated(since = "2.14.0")
public Item addReferencedLineID(String s) { public Item addReferencedLineID(String s) {
return addBuyerOrderReferencedDocumentLineID(s); return addBuyerOrderReferencedDocumentLineID(s);
} }

View File

@@ -1,6 +1,8 @@
package org.mustangproject; package org.mustangproject;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -161,7 +163,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty {
NodeList taxSchemechilds = partyTaxScheme.item(partyTaxSchemeIndex).getChildNodes(); NodeList taxSchemechilds = partyTaxScheme.item(partyTaxSchemeIndex).getChildNodes();
for (int taxSchemechildsIndex = 0; taxSchemechildsIndex < taxSchemechilds.getLength(); taxSchemechildsIndex++) { for (int taxSchemechildsIndex = 0; taxSchemechildsIndex < taxSchemechilds.getLength(); taxSchemechildsIndex++) {
if (taxSchemechilds.item(taxSchemechildsIndex).getLocalName() != null) { if (taxSchemechilds.item(taxSchemechildsIndex).getLocalName() != null) {
Set<String> taxSchemeTypes = new HashSet<>(Arrays.asList("FC", "NOVAT")); Set<String> taxSchemeTypes = Set.of("FC", "NOVAT");
String textContent = taxSchemechilds.item(taxSchemechildsIndex).getTextContent(); String textContent = taxSchemechilds.item(taxSchemechildsIndex).getTextContent();
if (textContent != null && taxSchemeTypes.contains(textContent)) { if (textContent != null && taxSchemeTypes.contains(textContent)) {
setTaxID(CompanyId); setTaxID(CompanyId);

View File

@@ -282,7 +282,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
itemVATAmount.setVatExemptionReasonText(reasonText); itemVATAmount.setVatExemptionReasonText(reasonText);
} }
final Optional<VATAmount> currentVatAmount = this.getCurrentVatAmount(vatAmounts, currentItem.getProduct().getTaxCategoryCode(), percent); final Optional<VATAmount> currentVatAmount = this.getCurrentVatAmount(vatAmounts, currentItem.getProduct().getTaxCategoryCode(), percent);
if (!currentVatAmount.isPresent()) { if (currentVatAmount.isEmpty()) {
vatAmounts.add(itemVATAmount); vatAmounts.add(itemVATAmount);
} else { } else {
this.mergeAdding(currentVatAmount.get(), itemVATAmount); this.mergeAdding(currentVatAmount.get(), itemVATAmount);
@@ -299,7 +299,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
final BigDecimal chargeBasis = currentCharge.getTotalAmount(this); final BigDecimal chargeBasis = currentCharge.getTotalAmount(this);
final VATAmount chargeVatAmount = new VATAmount(chargeBasis, chargeBasis.multiply(taxPercent.divide(new BigDecimal(100))), vatCategoryCode, final VATAmount chargeVatAmount = new VATAmount(chargeBasis, chargeBasis.multiply(taxPercent.divide(new BigDecimal(100))), vatCategoryCode,
vatDueDateTypeCode, taxPercent); vatDueDateTypeCode, taxPercent);
if (!currentChargeVatAmount.isPresent()) { if (currentChargeVatAmount.isEmpty()) {
vatAmounts.add(chargeVatAmount); vatAmounts.add(chargeVatAmount);
} else { } else {
this.mergeAdding(currentChargeVatAmount.get(), chargeVatAmount); this.mergeAdding(currentChargeVatAmount.get(), chargeVatAmount);
@@ -319,7 +319,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
allowanceNegativeBasis.multiply(taxPercent.divide(new BigDecimal(100))), allowanceNegativeBasis.multiply(taxPercent.divide(new BigDecimal(100))),
currentAllowance.getCategoryCode() != null ? currentAllowance.getCategoryCode() : "S", currentAllowance.getCategoryCode() != null ? currentAllowance.getCategoryCode() : "S",
vatDueDateTypeCode, taxPercent); vatDueDateTypeCode, taxPercent);
if (!currentAllowanceVatAmount.isPresent()) { if (currentAllowanceVatAmount.isEmpty()) {
vatAmounts.add(allowanceVATAmount); vatAmounts.add(allowanceVATAmount);
} else { } else {
this.mergeAdding(currentAllowanceVatAmount.get(), allowanceVATAmount); this.mergeAdding(currentAllowanceVatAmount.get(), allowanceVATAmount);
@@ -333,13 +333,10 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
public void mergeAdding(VATAmount vatAmount, VATAmount toAdd) { public void mergeAdding(VATAmount vatAmount, VATAmount toAdd) {
vatAmount.setBasis(vatAmount.getBasis().add(toAdd.getBasis())); vatAmount.setBasis(vatAmount.getBasis().add(toAdd.getBasis()));
vatAmount.setCalculated(vatAmount.getCalculated().add(toAdd.getCalculated())); vatAmount.setCalculated(vatAmount.getCalculated().add(toAdd.getCalculated()));
if (toAdd.getVatExemptionReasonText() != null && !toAdd.getVatExemptionReasonText().trim().isEmpty()) { if (toAdd.getVatExemptionReasonText() != null && !toAdd.getVatExemptionReasonText().isBlank()) {
Optional<String> text = Optional.ofNullable(vatAmount.getVatExemptionReasonText()).filter(reasonText -> !reasonText.equals(toAdd.getVatExemptionReasonText())); Optional.ofNullable(vatAmount.getVatExemptionReasonText()).filter(reasonText -> !reasonText.equals(toAdd.getVatExemptionReasonText())).ifPresentOrElse(
if (text.isPresent()) { text -> vatAmount.setVatExemptionReasonText(String.join(", ", text, toAdd.getVatExemptionReasonText())),
vatAmount.setVatExemptionReasonText(String.join(", ", text.get(), toAdd.getVatExemptionReasonText())); () -> vatAmount.setVatExemptionReasonText(toAdd.getVatExemptionReasonText()));
} else {
vatAmount.setVatExemptionReasonText(toAdd.getVatExemptionReasonText());
}
} }
} }

View File

@@ -76,7 +76,7 @@ public class ValidationLogVisualizer {
LOGGER.error("Failed to create PDF", e1); LOGGER.error("Failed to create PDF", e1);
} }
return new String(baos.toByteArray(), StandardCharsets.UTF_8); return baos.toString(StandardCharsets.UTF_8);
} }
public byte[] createPDFBytes(String xmlLogfileContent) { public byte[] createPDFBytes(String xmlLogfileContent) {

View File

@@ -56,7 +56,7 @@ public class XMLUpgrader {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
applySchematronXsl(new FileInputStream(xmlFilename), baos); applySchematronXsl(new FileInputStream(xmlFilename), baos);
String res = null; String res = null;
res = new String(baos.toByteArray(), StandardCharsets.UTF_8); res = baos.toString(StandardCharsets.UTF_8);
return res; return res;
} }

View File

@@ -385,7 +385,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
} }
String businessProcessId = trans.getBusinessProcessId(); String businessProcessId = trans.getBusinessProcessId();
if (businessProcessId != null && !businessProcessId.trim().isEmpty()) { if (businessProcessId != null && !businessProcessId.isBlank()) {
xml += "<ram:BusinessProcessSpecifiedDocumentContextParameter>\n" xml += "<ram:BusinessProcessSpecifiedDocumentContextParameter>\n"
+ "<ram:ID>" + XMLTools.encodeXML(businessProcessId) + "</ram:ID>\n" + "<ram:ID>" + XMLTools.encodeXML(businessProcessId) + "</ram:ID>\n"
+ "</ram:BusinessProcessSpecifiedDocumentContextParameter>\n"; + "</ram:BusinessProcessSpecifiedDocumentContextParameter>\n";

View File

@@ -36,7 +36,16 @@ import java.nio.file.Paths;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -237,14 +246,14 @@ public class ZUGFeRDInvoiceImporter {
*/ */
final PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile(); final PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
Set<String> validFilenames = new HashSet<>(Arrays.asList( Set<String> validFilenames = Set.of(
"ZUGFeRD-invoice.xml", "ZUGFeRD-invoice.xml",
"zugferd-invoice.xml", "zugferd-invoice.xml",
"factur-x.xml", "factur-x.xml",
"xrechnung.xml", "xrechnung.xml",
"order-x.xml", "order-x.xml",
"cida.xml" "cida.xml"
)); );
if (validFilenames.contains(filename)) { if (validFilenames.contains(filename)) {
containsMeta = true; containsMeta = true;
@@ -635,7 +644,7 @@ public class ZUGFeRDInvoiceImporter {
zpp.addNotes(includedNotes); zpp.addNotes(includedNotes);
String rootNode = extractString("local-name(/*)"); String rootNode = extractString("local-name(/*)");
String potentialCashDiscountTerms=null; String potentialCashDiscountTerms=null;
if (rootNode != null && new HashSet<>(Arrays.asList("Invoice", "CreditNote")).contains(rootNode)) { if (rootNode != null && Set.of("Invoice", "CreditNote").contains(rootNode)) {
// UBL... // UBL...
// //*[local-name()="Invoice" or local-name()="CreditNote"] // //*[local-name()="Invoice" or local-name()="CreditNote"]
number = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"ID\"]").trim(); number = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"ID\"]").trim();
@@ -1365,7 +1374,7 @@ public class ZUGFeRDInvoiceImporter {
if (whichType != EStandard.despatchadvice && !ignoreCalculationErrors) { if (whichType != EStandard.despatchadvice && !ignoreCalculationErrors) {
// Check calculation if document type allows it and calculation errors should not be ignored // Check calculation if document type allows it and calculation errors should not be ignored
String payableTotalFromXml = XMLTools.nDigitFormat(Objects.requireNonNull(duePayableAmount != null ? duePayableAmount : expectedGrandTotal), 2); String payableTotalFromXml = XMLTools.nDigitFormat(Objects.requireNonNullElse(duePayableAmount, expectedGrandTotal), 2);
if (!calculatedPayableTotal.equals(payableTotalFromXml)) { if (!calculatedPayableTotal.equals(payableTotalFromXml)) {
String moreDetails = ""; String moreDetails = "";
try { try {

View File

@@ -142,7 +142,7 @@ public class ZUGFeRDVisualizer {
if (thestandard == EStandard.zugferd) { if (thestandard == EStandard.zugferd) {
applyZF1XSLT(xmlContentStream, htmlOutput); applyZF1XSLT(xmlContentStream, htmlOutput);
return new String(htmlOutput.toByteArray(), StandardCharsets.UTF_8); return htmlOutput.toString(StandardCharsets.UTF_8);
} else if (thestandard == EStandard.facturx) { } else if (thestandard == EStandard.facturx) {
//zf2 or fx //zf2 or fx
applyZF2XSLT(xmlContentStream, htmlOutput); applyZF2XSLT(xmlContentStream, htmlOutput);
@@ -164,7 +164,7 @@ public class ZUGFeRDVisualizer {
applyXSLTToHTML(in.get(), htmlOutStream, lang); applyXSLTToHTML(in.get(), htmlOutStream, lang);
} }
return new String(htmlOutStream.toByteArray(), StandardCharsets.UTF_8); return htmlOutStream.toString(StandardCharsets.UTF_8);
} }
/** /**
@@ -258,7 +258,7 @@ public class ZUGFeRDVisualizer {
if (in.isPresent()) { if (in.isPresent()) {
applyXSLTToPDF(in.get(), baos, lang); applyXSLTToPDF(in.get(), baos, lang);
} }
return new String(baos.toByteArray(), StandardCharsets.UTF_8); return baos.toString(StandardCharsets.UTF_8);
} }
public void toPDF(String xmlFilename, String pdfFilename) { public void toPDF(String xmlFilename, String pdfFilename) {

View File

@@ -66,7 +66,7 @@ public class BackwardCompatibilityTest extends TestCase implements IExportableTr
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos); ze.export(baos);
ze.close(); ze.close();
String pdfContent = new String(baos.toByteArray(), StandardCharsets.UTF_8); String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1); assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
// check for pdf-a schema extension // check for pdf-a schema extension
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1); // assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
@@ -106,7 +106,7 @@ public class BackwardCompatibilityTest extends TestCase implements IExportableTr
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos); ze.export(baos);
ze.close(); ze.close();
String pdfContent = new String(baos.toByteArray(), StandardCharsets.UTF_8); String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1); assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
// check for pdf-a schema extension // check for pdf-a schema extension
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1); // assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
@@ -144,7 +144,7 @@ public class BackwardCompatibilityTest extends TestCase implements IExportableTr
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos); ze.export(baos);
ze.close(); ze.close();
String pdfContent = new String(baos.toByteArray(), StandardCharsets.UTF_8); String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1); assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
// check for pdf-a schema extension // check for pdf-a schema extension
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1); // assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);

View File

@@ -63,10 +63,10 @@ public class DeSerializationTest extends ResourceCase {
public void testProduct() throws IOException, XPathExpressionException, ParseException { public void testProduct() throws IOException, XPathExpressionException, ParseException {
File inputCII = getResourceAsFile("Extended_fremdwaehrung.xml"); File inputCII = getResourceAsFile("Extended_fremdwaehrung.xml");
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(); var zii = new ZUGFeRDInvoiceImporter();
zii.doIgnoreCalculationErrors(); zii.doIgnoreCalculationErrors();
zii.fromXML(new String(Files.readAllBytes(inputCII.toPath()))); zii.fromXML(Files.readString(inputCII.toPath()));
IZUGFeRDExportableProduct product = zii.extractInvoice() var product = zii.extractInvoice()
.getZFItems()[0] .getZFItems()[0]
.getProduct(); .getProduct();

View File

@@ -271,7 +271,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
zea1.export(TARGET_PDF); zea1.export(TARGET_PDF);
zea1.export(baos); zea1.export(baos);
zea1.close(); zea1.close();
String pdfContent = new String(baos.toByteArray(), StandardCharsets.UTF_8); String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1); assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
assertFalse(pdfContent.indexOf("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>") == -1); assertFalse(pdfContent.indexOf("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>") == -1);
@@ -460,7 +460,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase {
zea1.export(TARGET_PDF); zea1.export(TARGET_PDF);
zea1.export(baos); zea1.export(baos);
zea1.close(); zea1.close();
String pdfContent = new String(baos.toByteArray(), StandardCharsets.UTF_8); String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1); assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>BASIC</zf:ConformanceLevel>") == -1); assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>BASIC</zf:ConformanceLevel>") == -1);

View File

@@ -373,7 +373,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
ze.export(baos); ze.export(baos);
ze.close(); ze.close();
String pdfContent = new String(baos.toByteArray(), StandardCharsets.UTF_8); String pdfContent = baos.toString(StandardCharsets.UTF_8);
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1); assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
// check for pdf-a schema extension // check for pdf-a schema extension
// assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1); // assertFalse(pdfContent.indexOf("<zf:ConformanceLevel>EN 16931</zf:ConformanceLevel>") == -1);
@@ -445,7 +445,7 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
result.write(buffer, 0, length); result.write(buffer, 0, length);
} }
byte[] bytes = result.toByteArray(); var bytes = result.toByteArray();
ze.addAdditionalFile("test.pdf", bytes); ze.addAdditionalFile("test.pdf", bytes);
ze.setTransaction(this); ze.setTransaction(this);

View File

@@ -90,7 +90,7 @@ public class UBLTest extends ResourceCase {
final ByteArrayOutputStream baos=new ByteArrayOutputStream(); final ByteArrayOutputStream baos=new ByteArrayOutputStream();
oe.export(baos); oe.export(baos);
final String theXML = new String(baos.toByteArray(), StandardCharsets.UTF_8); final String theXML = baos.toString(StandardCharsets.UTF_8);
assertTrue(theXML.contains("<DespatchAdvice")); assertTrue(theXML.contains("<DespatchAdvice"));
Files.write(Paths.get(TARGET_XML), theXML.getBytes(StandardCharsets.UTF_8)); Files.write(Paths.get(TARGET_XML), theXML.getBytes(StandardCharsets.UTF_8));
} catch (final IOException e) { } catch (final IOException e) {

View File

@@ -28,7 +28,7 @@
<github.global.server>github</github.global.server> <github.global.server>github</github.global.server>
<additionalparam>-Xdoclint:none</additionalparam> <additionalparam>-Xdoclint:none</additionalparam>
<!-- Skip error check for javadoc --> <!-- Skip error check for javadoc -->
<maven.compiler.release>8</maven.compiler.release> <maven.compiler.release>11</maven.compiler.release>
<maven.deploy.skip>true</maven.deploy.skip><!-- prevent this to be deployed to maven central as "core", <maven.deploy.skip>true</maven.deploy.skip><!-- prevent this to be deployed to maven central as "core",
we only want submodules, see also https://stackoverflow.com/questions/7446599/how-to-deploy-only-the-sub-modules-using-maven-deploy--> we only want submodules, see also https://stackoverflow.com/questions/7446599/how-to-deploy-only-the-sub-modules-using-maven-deploy-->
@@ -247,7 +247,7 @@
<configuration> <configuration>
<toolchains> <toolchains>
<jdk> <jdk>
<version>8</version> <version>11</version>
<vendor>adopt</vendor> <vendor>adopt</vendor>
</jdk> </jdk>
</toolchains> </toolchains>

View File

@@ -200,7 +200,7 @@ public class PDFValidator extends Validator {
for (int i = 0; i < nodes.getLength(); i++) { for (int i = 0; i < nodes.getLength(); i++) {
Node item = nodes.item(i); Node item = nodes.item(i);
String textContent = item.getTextContent(); String textContent = item.getTextContent();
if (textContent != null && new HashSet<>(Arrays.asList("INVOICE", "ORDER", "ORDER_RESPONSE", "ORDER_CHANGE").contains(textContent)) { if (textContent != null && Set.of("INVOICE", "ORDER", "ORDER_RESPONSE", "ORDER_CHANGE").contains(textContent)) {
documentTypeValid = true; documentTypeValid = true;
} }
} }

View File

@@ -227,7 +227,7 @@ public class XMLValidator extends Validator {
if (isBasicWithoutLines) { if (isBasicWithoutLines) {
isBasic = false;// basicwl also contains the string basic... isBasic = false;// basicwl also contains the string basic...
} }
isEN16931 = new HashSet<>(Arrays.asList( isEN16931 = Set.of(
"urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931", "urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931",
"urn:cen.eu:en16931:2017" "urn:cen.eu:en16931:2017"
) )
@@ -297,7 +297,7 @@ public class XMLValidator extends Validator {
//validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "ZF_211/EN16931/FACTUR-X_EN16931.xsd", 18, EPart.fx); //validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "ZF_211/EN16931/FACTUR-X_EN16931.xsd", 18, EPart.fx);
String xrVersion = contextProfile.substring(contextProfile.length() - 3).replace(".", ""); String xrVersion = contextProfile.substring(contextProfile.length() - 3).replace(".", "");
Set<String> supportedVersions = new HashSet<>(Arrays.asList("12", "20", "21", "22", "23", "30"); Set<String> supportedVersions = Set.of("12", "20", "21", "22", "23", "30");
if (!supportedVersions.contains(xrVersion)) { if (!supportedVersions.contains(xrVersion)) {
throw new Exception("Unsupported XR version"); throw new Exception("Unsupported XR version");
} }
@@ -311,7 +311,7 @@ public class XMLValidator extends Validator {
} else if ("CrossIndustryDocument".equalsIgnoreCase(rootLocalName)) { // ZUGFeRD 1.0 } else if ("CrossIndustryDocument".equalsIgnoreCase(rootLocalName)) { // ZUGFeRD 1.0
context.setGeneration("1"); context.setGeneration("1");
// //
Set<String> validZF1Profiles = new HashSet<>(Arrays.asList( Set<String> validZF1Profiles = Set.of(
"urn:ferd:CrossIndustryDocument:invoice:1p0:basic", "urn:ferd:CrossIndustryDocument:invoice:1p0:basic",
"urn:ferd:CrossIndustryDocument:invoice:1p0:comfort", "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort",
"urn:ferd:CrossIndustryDocument:invoice:1p0:extended" "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"
@@ -329,7 +329,7 @@ public class XMLValidator extends Validator {
if ("CII".equals(context.getFormat())) { if ("CII".equals(context.getFormat())) {
if ("2".equals(context.getGeneration())) { if ("2".equals(context.getGeneration())) {
Set<String> validZF2Profiles = new HashSet<>(Arrays.asList( Set<String> validZF2Profiles = Set.of(
"urn:factur-x.eu:1p0:minimum", "urn:factur-x.eu:1p0:minimum",
"urn:zugferd.de:2p0:minimum", "urn:zugferd.de:2p0:minimum",
"urn:factur-x.eu:1p0:basicwl", "urn:factur-x.eu:1p0:basicwl",
@@ -346,7 +346,7 @@ public class XMLValidator extends Validator {
} else /** v1 */ { } else /** v1 */ {
if (isOrderX) { if (isOrderX) {
//order-x 1.0 //order-x 1.0
if(new HashSet<>(Arrays.asList( if(Set.of(
"urn:order-x.eu:1p0:basic", "urn:order-x.eu:1p0:basic",
"urn:order-x.eu:1p0:comfort", "urn:order-x.eu:1p0:comfort",
"urn:order-x.eu:1p0:extended" "urn:order-x.eu:1p0:extended"
@@ -354,7 +354,7 @@ public class XMLValidator extends Validator {
addUnsupportedProfileResultItem(); addUnsupportedProfileResultItem();
} }
} else if (new HashSet<>(Arrays.asList( } else if (Set.of(
"urn:ferd:CrossIndustryDocument:invoice:1p0:basic", "urn:ferd:CrossIndustryDocument:invoice:1p0:basic",
"urn:ferd:CrossIndustryDocument:invoice:1p0:comfort", "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort",
"urn:ferd:CrossIndustryDocument:invoice:1p0:extended" "urn:ferd:CrossIndustryDocument:invoice:1p0:extended"

View File

@@ -4,6 +4,7 @@ import java.io.File;
import javax.xml.transform.Source; import javax.xml.transform.Source;
import org.junit.Test;
import org.xmlunit.builder.Input; import org.xmlunit.builder.Input;
import org.xmlunit.xpath.JAXPXPathEngine; import org.xmlunit.xpath.JAXPXPathEngine;
import org.xmlunit.xpath.XPathEngine; import org.xmlunit.xpath.XPathEngine;
@@ -459,6 +460,24 @@ public class XMLValidatorTest extends ResourceCase {
// ignore, will be in XML output anyway // ignore, will be in XML output anyway
} }
xv.context.clear();
tempFile = getResourceAsFile("X03_01_Abschlagsrechnung_SubInvoiceLine_u_LV_Nr.xml");
try {
xv.setFilename(tempFile.getAbsolutePath());
xv.validate();
String s = "<validation>" + xv.getXMLResult() + "</validation>";
// hierarchy mismatch should produce at least one warning
assertThat(s).valueByXPath("count(//warning)")
.asInt()
.isEqualTo(0);
} catch (final IrrecoverableValidationError e) {
// ignore, will be in XML output anyway
}
} }
} }

View File

@@ -0,0 +1,466 @@
<?xml version='1.0' encoding='UTF-8'?>
<!--English disclaimer below.-->
<!--
Nutzungsrechte
ZUGFeRD Datenformat Version 2.4.0, 29.10.2025
Beispiel Version 29.10.2025
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.4.0, October 29th, 2025
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:a="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" 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: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>210111 mit LV</ram:ID>
<ram:TypeCode>875</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20260530</udt:DateTimeString>
</ram:IssueDateTime>
<ram:IncludedNote>
<ram:Content>1. Abschlagsrechnung</ram:Content>
<ram:SubjectCode>ACB</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>Geschäftsführer: Herr Geschäftsführer , Muster Bau GmbH etc.</ram:Content>
<ram:SubjectCode>REG</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>Es bestehen Vereinbarungen, aus denen sich Minderungen des Entgelts ergeben können.</ram:Content>
<ram:SubjectCode>AAI</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>ZUGFeRD vers 2.4.0 Extended</ram:Content>
<ram:SubjectCode>ACB</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>Dies ist eine Beispiel-Rechnung zur Darstellung einer Bau-Abschlags-Rechnung mit Sub-Invoice-Lines und Leistungsverzeichnis-Bezug je Position</ram:Content>
<ram:SubjectCode>ACB</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>Betreff zum LV für eine Kurzinformation zum Bauvorhaben BT-22</ram:Content>
<ram:SubjectCode>ACB</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>Kopftext für zusätzliche Beschreibungen zur Rechnung. Z.B. als Anschreiben für die Rechnung BT-22</ram:Content>
<ram:SubjectCode>ACB</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>ergänzneder Fußtext für die Rechnung mit zusätzlichen Angaben. Z.B: Ist kein gesondertes Lieferdatum angegeben, entspricht das Rechnungsdatum dem Datum der Lieferung und Leistung</ram:Content>
<ram:SubjectCode>ACB</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>freier Text zur Rechnung BT-22</ram:Content>
<ram:SubjectCode>ACB</ram:SubjectCode>
</ram:IncludedNote>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>01.01</ram:LineID>
<ram:ParentLineID>01</ram:ParentLineID>
<ram:LineStatusReasonCode>GROUP</ram:LineStatusReasonCode>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Baugelände abräumen Anfallender Schutt, Pflanzenreste und Müll entsorgen</ram:Name>
</ram:SpecifiedTradeProduct>
<!-- <ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>7.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">300.00</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery> -->
<ram:SpecifiedLineTradeSettlement>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>2100.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>01.01.01</ram:LineID>
<ram:ParentLineID>01.01</ram:ParentLineID>
<ram:LineStatusReasonCode>DETAIL</ram:LineStatusReasonCode>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Baugelände abräumen</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>LV 1.1.1.1.1.</ram:IssuerAssignedID>
<ram:LineID>LV_01.01.01</ram:LineID>
<ram:TypeCode>130</ram:TypeCode>
<ram:Name>Leistungsverzeichnis</ram:Name>
<ram:ReferenceTypeCode>BD</ram:ReferenceTypeCode>
</ram:AdditionalReferencedDocument>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>7.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">100.00</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>700.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>01.01.02</ram:LineID>
<ram:ParentLineID>01.01</ram:ParentLineID>
<ram:LineStatusReasonCode>DETAIL</ram:LineStatusReasonCode>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Anfallender Pflanzenreste entsorgen</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>LV 1.1.1.1.1.</ram:IssuerAssignedID>
<ram:LineID>LV01.01.02</ram:LineID>
<ram:TypeCode>130</ram:TypeCode>
<ram:Name>Leistungsverzeichnis</ram:Name>
<ram:ReferenceTypeCode>BD</ram:ReferenceTypeCode>
</ram:AdditionalReferencedDocument>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>7.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">100.00</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>700.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>01.01.03</ram:LineID>
<ram:ParentLineID>01.01</ram:ParentLineID>
<ram:LineStatusReasonCode>DETAIL</ram:LineStatusReasonCode>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Müll entsorgen</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>LV 1.1.1.1.1.</ram:IssuerAssignedID>
<ram:LineID>LV01.01.03</ram:LineID>
<ram:TypeCode>130</ram:TypeCode>
<ram:Name>Leistungsverzeichnis</ram:Name>
<ram:ReferenceTypeCode>BD</ram:ReferenceTypeCode>
</ram:AdditionalReferencedDocument>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>7.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">100.00</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>700.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>01.02</ram:LineID>
<ram:ParentLineID>01</ram:ParentLineID>
<ram:LineStatusReasonCode>DETAIL</ram:LineStatusReasonCode>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Pflasterfläche vorbereiten, Planum herstellen und verdichten</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>6.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="MTK">250.00</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>1500.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>01</ram:LineID>
<ram:LineStatusReasonCode>GROUP</ram:LineStatusReasonCode>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Summe 01 Bauabschnitt 1 - Vorarbeiten</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:BuyerOrderReferencedDocument>
<ram:LineID>000001</ram:LineID>
</ram:BuyerOrderReferencedDocument>
</ram:SpecifiedLineTradeAgreement>
<!-- <ram:NetPriceProductTradePrice>
<ram:ChargeAmount>3600</ram:ChargeAmount>
<ram:BasisQuantity unitCode="H87">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">1.00</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery> -->
<ram:SpecifiedLineTradeSettlement>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>3600.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:BuyerReference>Kundenref. BT-10</ram:BuyerReference>
<ram:SellerTradeParty>
<ram:ID>998877</ram:ID>
<ram:Name>Musterbetrieb AG Demodaten</ram:Name>
<ram:SpecifiedLegalOrganization>
<ram:ID>HRA 45678</ram:ID>
</ram:SpecifiedLegalOrganization>
<ram:DefinedTradeContact>
<ram:PersonName>Kontaktperson</ram:PersonName>
<ram:TelephoneUniversalCommunication>
<ram:CompleteNumber>5578</ram:CompleteNumber>
</ram:TelephoneUniversalCommunication>
<ram:EmailURIUniversalCommunication>
<ram:URIID>absender@musterberieb.de</ram:URIID>
</ram:EmailURIUniversalCommunication>
</ram:DefinedTradeContact>
<ram:PostalTradeAddress>
<ram:PostcodeCode>37079</ram:PostcodeCode>
<ram:LineOne>August-Spindler-Strasse 222</ram:LineOne>
<ram:CityName>Göttingen</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE727081482</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:ID>330145</ram:ID>
<ram:Name>Auftraggeber Firmenkunde GmbH</ram:Name>
<ram:DefinedTradeContact>
<ram:PersonName>Herr Thomas Auftraggeber</ram:PersonName>
<ram:TelephoneUniversalCommunication>
<ram:CompleteNumber>+49 321 456789</ram:CompleteNumber>
</ram:TelephoneUniversalCommunication>
<ram:EmailURIUniversalCommunication>
<ram:URIID>thomas.auftraggeber@Firmenkunde.de</ram:URIID>
</ram:EmailURIUniversalCommunication>
</ram:DefinedTradeContact>
<ram:PostalTradeAddress>
<ram:PostcodeCode>37073</ram:PostcodeCode>
<ram:LineOne>Gartenstraße 1212</ram:LineOne>
<ram:CityName>Göttingen</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE106008386</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
<ram:SellerOrderReferencedDocument>
<ram:IssuerAssignedID>G12042-1-01</ram:IssuerAssignedID>
</ram:SellerOrderReferencedDocument>
<ram:BuyerOrderReferencedDocument>
<ram:IssuerAssignedID>BT-13</ram:IssuerAssignedID>
</ram:BuyerOrderReferencedDocument>
<ram:ContractReferencedDocument>
<ram:IssuerAssignedID>Vertragsnr. BT-12</ram:IssuerAssignedID>
</ram:ContractReferencedDocument>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>Vergabenr. BT-17</ram:IssuerAssignedID>
<ram:TypeCode>50</ram:TypeCode>
</ram:AdditionalReferencedDocument>
<ram:SpecifiedProcuringProject>
<ram:ID>Projektnr. BT-11</ram:ID>
<ram:Name>Project reference</ram:Name>
</ram:SpecifiedProcuringProject>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ShipToTradeParty>
<ram:Name>Auftraggeber Firmenkunde GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>37073</ram:PostcodeCode>
<ram:LineOne>Gartenstraße 1212</ram:LineOne>
<ram:CityName>Göttingen</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
</ram:ShipToTradeParty>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20260530</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementPaymentMeans>
<ram:TypeCode>58</ram:TypeCode>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>DE75512108001245126199</ram:IBANID>
<ram:AccountName>Musterbetrieb Kontoname</ram:AccountName>
</ram:PayeePartyCreditorFinancialAccount>
<ram:PayeeSpecifiedCreditorFinancialInstitution>
<ram:BICID>PBNKDEFF</ram:BICID>
</ram:PayeeSpecifiedCreditorFinancialInstitution>
</ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>684.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>3600.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:BillingSpecifiedPeriod>
<ram:StartDateTime>
<udt:DateTimeString format="102">20260513</udt:DateTimeString>
</ram:StartDateTime>
<ram:EndDateTime>
<udt:DateTimeString format="102">20260530</udt:DateTimeString>
</ram:EndDateTime>
</ram:BillingSpecifiedPeriod>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Bei Zahlung bis zum 06.06.2026 zahlen Sie mit 2,50 % Skonto € 4.176,90</ram:Description>
<ram:DueDateDateTime>
<udt:DateTimeString format="102">20260606</udt:DateTimeString>
</ram:DueDateDateTime>
<ram:ApplicableTradePaymentDiscountTerms>
<ram:BasisAmount>4284.00</ram:BasisAmount>
<ram:CalculationPercent>2.5</ram:CalculationPercent>
</ram:ApplicableTradePaymentDiscountTerms>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Bis zum zum 13.06.2026 ohne Abzug</ram:Description>
<ram:DueDateDateTime>
<udt:DateTimeString format="102">20260613</udt:DateTimeString>
</ram:DueDateDateTime>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>3600.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>3600.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">684.00</ram:TaxTotalAmount>
<ram:GrandTotalAmount>4284.00</ram:GrandTotalAmount>
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
<ram:DuePayableAmount>4284.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:ReceivableSpecifiedTradeAccountingAccount>
<ram:ID>Kostenstelle BT-19</ram:ID>
</ram:ReceivableSpecifiedTradeAccountingAccount>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>