Merge branch 'master' into parse_item_BillingSpecifiedPeriod

This commit is contained in:
ean
2025-02-03 09:48:35 +01:00
18 changed files with 874 additions and 75 deletions

View File

@@ -3,13 +3,13 @@
<parent>
<groupId>org.mustangproject</groupId>
<artifactId>core</artifactId>
<version>2.16.1-SNAPSHOT</version>
<version>2.16.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.mustangproject</groupId>
<artifactId>library</artifactId>
<version>2.16.1-SNAPSHOT</version>
<version>2.16.2-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
@@ -59,6 +59,12 @@
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<dependency>
<groupId>net.sf.offo</groupId>
<artifactId>fop-hyph</artifactId>
<version>2.0</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE -->
<dependency>
<groupId>net.sf.saxon</groupId>

View File

@@ -1,5 +1,6 @@
package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IZUGFeRDCashDiscount;
@@ -63,6 +64,7 @@ public class CashDiscount implements IZUGFeRDCashDiscount {
/***
* @return this particular cash discount as cross industry invoice XML
*/
@JsonIgnore
public String getAsCII() {
return "<ram:SpecifiedTradePaymentTerms>"+
"<ram:Description>Cash Discount</ram:Description>"+
@@ -78,6 +80,7 @@ public class CashDiscount implements IZUGFeRDCashDiscount {
* XRechnung CIUS defined it's own proprietary format for a freetext field
* @return this particular cash discount in proprietary xrechnung format
*/
@JsonIgnore
public String getAsXRechnung() {
return "#SKONTO#TAGE="+days+"#PROZENT="+XMLTools.nDigitFormat(percent,2)+"#\n";
}

View File

@@ -69,6 +69,7 @@ public class Invoice implements IExportableTransaction {
protected String vatDueDateTypeCode = null;
protected String creditorReferenceID; // required when direct debit is used.
private BigDecimal roundingAmount=null;
private String paymentReference; // Remittance information / Verwendungszweck, BT-83
public Invoice() {
ZFItems = new ArrayList<>();
@@ -650,6 +651,16 @@ public class Invoice implements IExportableTransaction {
return this;
}
@Override
public String getPaymentReference() {
return paymentReference;
}
public Invoice setPaymentReference(String paymentReference) {
this.paymentReference = paymentReference;
return this;
}
@Override
public TradeParty getDeliveryAddress() {
return deliveryAddress;
@@ -783,11 +794,20 @@ public class Invoice implements IExportableTransaction {
return detailedDeliveryDateStart;
}
public Invoice setDetailedDeliveryPeriodFrom(Date dt) {
detailedDeliveryDateStart=dt;
return this;
}
@Override
public Date getDetailedDeliveryPeriodTo() {
return detailedDeliveryPeriodEnd;
}
public Invoice setDetailedDeliveryPeriodTo(Date dt) {
detailedDeliveryPeriodEnd=dt;
return this;
}
/**
* adds a free text paragraph, which will become an includedNote element

View File

@@ -172,6 +172,9 @@ public class Item implements IZUGFeRDExportableItem {
icnm.getAsNodeMap("ApplicableTradeTax")
.flatMap(cnm -> cnm.getAsBigDecimal("RateApplicablePercent", "ApplicablePercent"))
.ifPresent(product::setVATPercent);
icnm.getAsNodeMap("ApplicableTradeTax")
.flatMap(cnm -> cnm.getAsString("ExemptionReason"))
.ifPresent(product::setTaxExemptionReason);
icnm.getAsNodeMap("SpecifiedTradeAllowanceCharge").ifPresent(stac -> {
stac.getAsNodeMap("ChargeIndicator").ifPresent(ci -> {
String isChargeString=ci.getAsString("Indicator").get();
@@ -187,8 +190,12 @@ public class Item implements IZUGFeRDExportableItem {
if (amountString!=null) {
izac.setTotalAmount(new BigDecimal(amountString));
}
if(percentString!=null) {
izac.setPercent(new BigDecimal(percentString));
}
if(reason!=null) {
izac.setReason(reason);
}
if (isChargeString.equalsIgnoreCase("false")) {
addAllowance(izac);

View File

@@ -314,6 +314,10 @@ public interface IExportableTransaction {
return null;
}
default String getPaymentReference() {
return null;
}
/**
* returns if a rebate agreements exists
*

View File

@@ -288,8 +288,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
final String allowanceChargeStr = "<ram:AppliedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" +
chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage +
"<ram:ActualAmount>" + priceFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount>" +
reason +
reasonCode +
reason +
"</ram:AppliedTradeAllowanceCharge>";
return allowanceChargeStr;
}
@@ -323,8 +323,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
final String itemTotalAllowanceChargeStr = "<ram:SpecifiedTradeAllowanceCharge><ram:ChargeIndicator><udt:Indicator>" +
chargeIndicator + "</udt:Indicator></ram:ChargeIndicator>" + percentage +
"<ram:ActualAmount>" + currencyFormat(allowance.getTotalAmount(item)) + "</ram:ActualAmount>" +
reason +
reasonCode +
reason +
"</ram:SpecifiedTradeAllowanceCharge>";
return itemTotalAllowanceChargeStr;
}
@@ -388,14 +388,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ "</ram:GuidelineSpecifiedDocumentContextParameter>"
+ "</rsm:ExchangedDocumentContext>"
+ "<rsm:ExchangedDocument>"
+ "<ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>"
// + "<ram:Name>RECHNUNG</ram:Name>"
// + "<ram:TypeCode>380</ram:TypeCode>"
+ "<ram:TypeCode>" + typecode + "</ram:TypeCode>"
+ "<ram:IssueDateTime>"
+ DATE.udtFormat(trans.getIssueDate()) + "</ram:IssueDateTime>" // date
+ "<ram:ID>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:ID>";
if (profile == Profiles.getByName("Extended") && trans.getDocumentName() != null) {
xml += "<ram:Name>" + XMLTools.encodeXML(trans.getDocumentName()) + "</ram:Name>";
}
xml += "<ram:TypeCode>" + typecode + "</ram:TypeCode>"
+ "<ram:IssueDateTime>" + DATE.udtFormat(trans.getIssueDate()) + "</ram:IssueDateTime>" // date
+ buildNotes(trans)
+ "</rsm:ExchangedDocument>"
+ "<rsm:SupplyChainTradeTransaction>";
int lineID = 0;
@@ -662,8 +661,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if ((trans.getCreditorReferenceID() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
xml += "<ram:CreditorReferenceID>" + XMLTools.encodeXML(trans.getCreditorReferenceID()) + "</ram:CreditorReferenceID>";
}
if ((trans.getNumber() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
xml += "<ram:PaymentReference>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:PaymentReference>";
if ((trans.getPaymentReference() != null) && (getProfile() != Profiles.getByName("Minimum"))) {
xml += "<ram:PaymentReference>" + XMLTools.encodeXML(trans.getPaymentReference()) + "</ram:PaymentReference>";
}
xml += "<ram:InvoiceCurrencyCode>" + trans.getCurrency() + "</ram:InvoiceCurrencyCode>";
if (this.trans.getPayee() != null) {
@@ -744,12 +743,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
"<udt:Indicator>true</udt:Indicator>" +
"</ram:ChargeIndicator>" +
"<ram:ActualAmount>" + currencyFormat(charge.getTotalAmount(calc)) + "</ram:ActualAmount>";
if (charge.getReason() != null) {
xml += "<ram:Reason>" + XMLTools.encodeXML(charge.getReason()) + "</ram:Reason>";
}
if (charge.getReasonCode() != null) {
xml += "<ram:ReasonCode>" + charge.getReasonCode() + "</ram:ReasonCode>";
}
if (charge.getReason() != null) {
xml += "<ram:Reason>" + XMLTools.encodeXML(charge.getReason()) + "</ram:Reason>";
}
xml += "<ram:CategoryTradeTax>" +
"<ram:TypeCode>VAT</ram:TypeCode>" +
"<ram:CategoryCode>" + charge.getCategoryCode() + "</ram:CategoryCode>";

View File

@@ -288,6 +288,7 @@ public class ZUGFeRDInvoiceImporter {
public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseException {
String number = "";
String documentName = null;
String typeCode = null;
String deliveryPeriodStart = null;
String deliveryPeriodEnd = null;
@@ -496,6 +497,9 @@ public class ZUGFeRDInvoiceImporter {
if ((item.getLocalName() != null) && (item.getLocalName().equals("ID"))) {
number = XMLTools.trimOrNull(item);
}
if ((item.getLocalName() != null) && (item.getLocalName().equals("Name"))) {
documentName = XMLTools.trimOrNull(item);
}
if ((item.getLocalName() != null) && (item.getLocalName().equals("TypeCode"))) {
typeCode = XMLTools.trimOrNull(item);
}
@@ -556,13 +560,13 @@ public class ZUGFeRDInvoiceImporter {
}
zpp.addNotes(includedNotes);
String rootNode = extractString("local-name(/*)");
if (rootNode.equals("Invoice")||rootNode.equals("CreditNote")) {
if (rootNode.equals("Invoice") || rootNode.equals("CreditNote")) {
// UBL...
// //*[local-name()="Invoice" or local-name()="CreditNote"]
number = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"ID\"]").trim();
typeCode = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"InvoiceTypeCode\"]").trim();
String issueDateStr = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"IssueDate\"]").trim();
if (issueDateStr.length()>0) {
if (issueDateStr.length() > 0) {
issueDate = new SimpleDateFormat("yyyy-MM-dd").parse(issueDateStr);
}
String dueDt = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"DueDate\"]").trim();
@@ -651,7 +655,7 @@ public class ZUGFeRDInvoiceImporter {
zpp.setCurrency(currency);
String paymentTermsDescription = extractString("//*[local-name()=\"SpecifiedTradePaymentTerms\"]/*[local-name()=\"Description\"]|//*[local-name()=\"PaymentTerms\"]/*[local-name()=\"Note\"]");
if ((paymentTermsDescription!=null)&&(!paymentTermsDescription.isEmpty())) {
if ((paymentTermsDescription != null) && (!paymentTermsDescription.isEmpty())) {
zpp.setPaymentTermDescription(paymentTermsDescription);
}
@@ -668,6 +672,12 @@ public class ZUGFeRDInvoiceImporter {
NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes();
for (int settlementChildIndex = 0; settlementChildIndex < headerTradeSettlementChilds.getLength(); settlementChildIndex++) {
if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
&& (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("PaymentReference"))) {
String paymentReference = headerTradeSettlementChilds.item(settlementChildIndex).getTextContent();
zpp.setPaymentReference(paymentReference);
}
if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null)
&& (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("SpecifiedTradePaymentTerms"))) {
NodeList paymentTermChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes();
@@ -802,7 +812,7 @@ public class ZUGFeRDInvoiceImporter {
}
zpp.setIssueDate(issueDate).setDueDate(dueDate).setDeliveryDate(deliveryDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentCode(typeCode);
zpp.setIssueDate(issueDate).setDueDate(dueDate).setDeliveryDate(deliveryDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentName(documentName).setDocumentCode(typeCode);
if ((directDebitMandateID != null) && (IBAN != null)) {
DirectDebit d = new DirectDebit(IBAN, directDebitMandateID);
@@ -848,15 +858,14 @@ public class ZUGFeRDInvoiceImporter {
Node currentItemNode = nodes.item(i);
ReferencedDocument doc = ReferencedDocument.fromNode(currentItemNode);
if (doc != null
&& (!Objects.equals(zpp.getInvoiceReferencedDocumentID(), doc.getIssuerAssignedID())
|| !Objects.equals(zpp.getInvoiceReferencedIssueDate(), doc.getFormattedIssueDateTime())))
{
if (doc != null
&& (!Objects.equals(zpp.getInvoiceReferencedDocumentID(), doc.getIssuerAssignedID())
|| !Objects.equals(zpp.getInvoiceReferencedIssueDate(), doc.getFormattedIssueDateTime()))) {
zpp.addInvoiceReferencedDocument(doc);
}
}
}
zpp.setOwnOrganisationName(extractString("//*[local-name()=\"SellerTradeParty\"]/*[local-name()=\"Name\"]|//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyName\"]").trim());
String rounding = extractString("//*[local-name()=\"SpecifiedTradeSettlementHeaderMonetarySummation\"]/*[local-name()=\"RoundingAmount\"]|//*[local-name()=\"LegalMonetaryTotal\"]/*[local-name()=\"Party\"]/*[local-name()=\"PayableRoundingAmount\"]");
@@ -890,7 +899,7 @@ public class ZUGFeRDInvoiceImporter {
xpr = xpath.compile("//*[local-name()=\"AttachmentBinaryObject\"]|//*[local-name()=\"EmbeddedDocumentBinaryObject\"]");
NodeList attachmentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < attachmentNodes.getLength(); i++) {
FileAttachment fa = new FileAttachment(attachmentNodes.item(i).getAttributes().getNamedItem("filename").getNodeValue(), attachmentNodes.item(i).getAttributes().getNamedItem("mimeCode").getNodeValue(), "Data", Base64.getDecoder().decode(XMLTools.trimOrNull(attachmentNodes.item(i))));
FileAttachment fa = new FileAttachment(attachmentNodes.item(i).getAttributes().getNamedItem("filename").getNodeValue(), attachmentNodes.item(i).getAttributes().getNamedItem("mimeCode").getNodeValue(), "Data", Base64.getMimeDecoder().decode(XMLTools.trimOrNull(attachmentNodes.item(i))));
zpp.embedFileInXML(fa);
// filename = "Aufmass.png" mimeCode = "image/png"
//EmbeddedDocumentBinaryObject cbc:EmbeddedDocumentBinaryObject mimeCode="image/png" filename="Aufmass.png"
@@ -976,6 +985,38 @@ public class ZUGFeRDInvoiceImporter {
}
}
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"SpecifiedLogisticsServiceCharge\"]");// UBL unknown
chargeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < chargeNodes.getLength(); i++) {
NodeList chargeNodeChilds = chargeNodes.item(i).getChildNodes();
String chargeAmount = null;
String taxPercent = null;
for (int chargeChildIndex = 0; chargeChildIndex < chargeNodeChilds.getLength(); chargeChildIndex++) {
String chargeChildName = chargeNodeChilds.item(chargeChildIndex).getLocalName();
if (chargeChildName != null) {
if (chargeChildName.equals("AppliedAmount")) {
chargeAmount = XMLTools.trimOrNull(chargeNodeChilds.item(chargeChildIndex));
} else if (chargeChildName.equals("AppliedTradeTax")) {
NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes();
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
String taxItemName = taxChilds.item(taxChildIndex).getLocalName();
if ((taxItemName != null) && (taxItemName.equals("RateApplicablePercent"))) {
taxPercent = XMLTools.trimOrNull(taxChilds.item(taxChildIndex));
}
}
}
}
//appliedAmount
//AppliedTradeTax
}
if (chargeAmount != null) {
Charge c = new Charge(new BigDecimal(chargeAmount));
if (taxPercent != null) {
c.setTaxPercent(new BigDecimal(taxPercent));
}
zpp.addCharge(c);
}
}
TransactionCalculator tc = new TransactionCalculator(zpp);
@@ -1040,7 +1081,7 @@ public class ZUGFeRDInvoiceImporter {
} else if (rootNode.equals("Invoice")) {
return EStandard.ubl;
} else if (rootNode.equals("CreditNote")) {
return EStandard.ubl;
return EStandard.ubl_creditnote;
} else if (rootNode.equals("CrossIndustryInvoice")) {
return EStandard.facturx;
} else if (rootNode.equals("SCRDMCCBDACIDAMessageStructure")) {
@@ -1085,11 +1126,17 @@ public class ZUGFeRDInvoiceImporter {
*
* @return the file attachments embedded in XML (using base64) decoded as byte array,
* for PDF embedded files in FX use getFileAttachmentsPDF()
* may return empty array
* @deprecated use invoice.getAdditionalReferencedDocuments
*/
@Deprecated
public List<FileAttachment> getFileAttachmentsXML() {
return new ArrayList<>(Arrays.asList(importedInvoice.getAdditionalReferencedDocuments()));
if (importedInvoice.getAdditionalReferencedDocuments()!=null) {
return new ArrayList<>(Arrays.asList(importedInvoice.getAdditionalReferencedDocuments()));
} else {
return new ArrayList<>();
}
}
/***

View File

@@ -45,6 +45,9 @@ import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class ZUGFeRDVisualizer {
@@ -254,16 +257,61 @@ public class ZUGFeRDVisualizer {
// the writing part
File XMLinputFile = new File(xmlFilename);
String result = null;
String fopInput = 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(XMLinputFile.getAbsolutePath());
fopInput = this.toFOP(XMLinputFile.getAbsolutePath());
} catch (TransformerException | IOException e) {
LOGGER.error("Failed to apply FOP", e);
}
toPDFfromFOP(fopInput, () -> {
try {
return new FileOutputStream(pdfFilename);
} catch (FileNotFoundException e) {
LOGGER.error("Failed to create PDF", e);
}
return null;
}, (OutputStream out) -> {});
}
public byte[] toPDF(String xmlContent) {
String fopInput = null;
/* remove file endings so that tests can also pass after checking
out from git with arbitrary options (which may include CSRF changes)
*/
try {
ByteArrayInputStream fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));
EStandard theStandard = findOutStandardFromRootNode(fis);
fis = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8));//rewind :-(
fopInput = toFOP(fis, theStandard);
} catch (TransformerException | IOException e) {
LOGGER.error("Failed to apply FOP", e);
}
AtomicReference<byte[]> byteHolder = new AtomicReference<>();
ByteArrayOutputStream os = new ByteArrayOutputStream();
toPDFfromFOP(fopInput, () -> new BufferedOutputStream(os), (OutputStream out) -> {
try {
out.flush();
} catch (IOException e) {
LOGGER.error("Failed to create PDF", e);
}
byteHolder.set(os.toByteArray());
});
return byteHolder.get();
}
private void toPDFfromFOP(String fopInput, Supplier<OutputStream> outputStreamDelegate, Consumer<OutputStream> consumerDelegate) {
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
Configuration cfg = null;
@@ -291,7 +339,7 @@ public class ZUGFeRDVisualizer {
// Step 2: Set up output stream.
// Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams).
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(pdfFilename))) {
try (OutputStream out = new BufferedOutputStream(outputStreamDelegate.get())) {
// Step 3: Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out);
@@ -302,13 +350,15 @@ public class ZUGFeRDVisualizer {
// Step 5: Setup input and output for XSLT transformation
// Setup input stream
Source src = new StreamSource(new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8)));
Source src = new StreamSource(new ByteArrayInputStream(fopInput.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);
consumerDelegate.accept(out);
} catch (FOPException | IOException | TransformerException e) {
LOGGER.error("Failed to create PDF", e);

View File

@@ -28,6 +28,14 @@
<xsl:text>red</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:variable name="xml_result_text">
<xsl:if test="/validation/xml/summary/@status = 'valid'">
<xsl:text>Das XML ist valide.</xsl:text>
</xsl:if>
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
<xsl:text>Das XML ist nicht valide.</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>
@@ -37,18 +45,26 @@
</xsl:if>
</xsl:variable>
<xsl:variable name="pdf_result_text">
<xsl:if test="/validation/xml/summary/@status = 'valid'">
<xsl:if test="/validation/pdf/summary/@status = 'valid'">
<xsl:text>Das ZUGFeRD-PDF ist valide.</xsl:text>
</xsl:if>
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
<xsl:if test="/validation/pdf/summary/@status = 'invalid'">
<xsl:text>Das ZUGFeRD-PDF ist nicht valide.</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:variable name="result_color">
<xsl:if test="/validation/summary/@status = 'valid'">
<xsl:text>green</xsl:text>
</xsl:if>
<xsl:if test="/validation/summary/@status = 'invalid'">
<xsl:text>red</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:variable name="result_text">
<xsl:if test="/validation/xml/summary/@status = 'valid'">
<xsl:if test="/validation/summary/@status = 'valid'">
<xsl:text>Es wird empfohlen, das Dokument anzunehmen und es weiterzuverarbeiten.</xsl:text>
</xsl:if>
<xsl:if test="/validation/xml/summary/@status = 'invalid'">
<xsl:if test="/validation/summary/@status = 'invalid'">
<xsl:text>Es wird empfohlen, das Dokument zurückzuweisen.</xsl:text>
</xsl:if>
</xsl:variable>
@@ -118,6 +134,7 @@
</fo:table-body>
</fo:table>
<xsl:apply-templates select="./pdf"/>
<xsl:apply-templates select="./xml"/>
<!--
<xsl:call-template name="SubHeader">
<xsl:with-param name="text"
@@ -130,7 +147,7 @@
<xsl:with-param name="text"
select="concat('Bewertung: ', $result_text)"/>
<xsl:with-param name="color"
select="$xml_result_color"/>
select="$result_color"/>
</xsl:call-template>
<fo:block>Validierungsergebnisse im Detail:</fo:block>
<fo:table>
@@ -165,8 +182,8 @@
page-break-before="auto"
page-break-inside="avoid">
<xsl:choose>
<xsl:when test="./xml/messages">
<xsl:apply-templates select="./xml/messages"/>
<xsl:when test="./pdf/messages|./xml/messages|./messages">
<xsl:apply-templates select="./pdf/messages|./xml/messages|./messages"/>
</xsl:when>
<xsl:otherwise>
<fo:table-row border-style="solid"
@@ -185,10 +202,10 @@
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="notice|warning|error">
<xsl:template match="notice|warning|error|exception|fatal">
<xsl:variable name="msg_color">
<xsl:choose>
<xsl:when test="name() = 'error'">
<xsl:when test="name() = 'error' or name() = 'exception' or name() = 'fatal'">
<xsl:text>red</xsl:text>
</xsl:when>
<xsl:when test="name() = 'warning'">
@@ -201,7 +218,7 @@
</xsl:variable>
<xsl:variable name="msg_label">
<xsl:choose>
<xsl:when test="name() = 'error'">
<xsl:when test="name() = 'error' or name() = 'exception' or name() = 'fatal'">
<xsl:text>Fehler</xsl:text>
</xsl:when>
<xsl:when test="name() = 'warning'">
@@ -291,7 +308,15 @@
<xsl:with-param name="text"
select="concat('ZUGFeRD-PDF: ', $pdf_result_text)"/>
<xsl:with-param name="color"
select="'black'"/>
select="$pdf_result_color"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="xml">
<xsl:call-template name="SubHeader">
<xsl:with-param name="text"
select="concat('E-Rechnung XML: ', $xml_result_text)"/>
<xsl:with-param name="color"
select="$xml_result_color"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="SubHeader">

View File

@@ -21,26 +21,35 @@
*/
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;
import java.util.TimeZone;
import javax.xml.xpath.XPathExpressionException;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import org.mustangproject.Allowance;
import org.mustangproject.BankDetails;
import org.mustangproject.CalculatedInvoice;
import org.mustangproject.CashDiscount;
import org.mustangproject.Charge;
import org.mustangproject.Contact;
import org.mustangproject.Invoice;
import org.mustangproject.Item;
import org.mustangproject.Product;
import org.mustangproject.SchemedID;
import org.mustangproject.TradeParty;
import org.mustangproject.ZUGFeRD.model.EventTimeCodeTypeConstants;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class DeSerializationTest extends ResourceCase {
@@ -102,6 +111,8 @@ public class DeSerializationTest extends ResourceCase {
" \"currency\": \"EUR\",\n" +
" \"issueDate\": \"2018-03-03T23:00:00.000+00:00\",\n" +
" \"deliveryDate\": \"2018-03-03T23:00:00.000+00:00\",\n" +
" \"detailedDeliveryPeriodFrom\": \"2017-03-03T13:00:00.000+00:00\",\n" +
" \"detailedDeliveryPeriodTo\": \"2017-03-04T13:00:00.000+00:00\",\n" +
" \"sender\": {\n" +
" \"name\": \"Lieferant GmbH\",\n" +
" \"zip\": \"80333\",\n" +
@@ -162,7 +173,15 @@ public class DeSerializationTest extends ResourceCase {
TransactionCalculator tc = new TransactionCalculator(fromJSON);
assertEquals(tc.getGrandTotal(), new BigDecimal("234.43"));
assertEquals(fromJSON.getNumber(), fromJSON.getNumber());
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
zf2p.setProfile(Profiles.getByName("XRechnung"));
zf2p.generateXML(fromJSON);
String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8);
assertEquals(fromJSON.getZFItems().length, fromJSON.getZFItems().length);
assertTrue(theXML.contains("20170303"));
assertTrue(theXML.contains("20170304"));
}
@@ -213,7 +232,7 @@ public class DeSerializationTest extends ResourceCase {
"\n" +
" \"number\": \"471102\",\n" +
" \"currency\": \"EUR\",\n" +
" \"issueDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
" \"issueDate\": \"2018-03-04T00:00:00.000\",\n" +
" \"dueDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
" \"deliveryDate\": \"2018-03-04T00:00:00.000+01:00\",\n" +
" \"sender\": {\n" +

View File

@@ -94,7 +94,7 @@ public class XRTest extends TestCase {
.addCashDiscount(new CashDiscount(new BigDecimal(3), 14))
.setReferenceNumber("991-01484-64")//leitweg-id
// not using any VAT, this is also a test of zero-rated goods:
.setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO), amount, new BigDecimal(1.0)))
.setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO).setTaxExemptionReason("Kleinunternehmer"), amount, new BigDecimal(1.0)))
.setPayee( new TradeParty().setName("VR Factoring GmbH").setID("DE813838785").setLegalOrganisation(new LegalOrganisation("391200LDDFJDMIPPMZ54", "0199")))
.embedFileInXML(fe1);

View File

@@ -259,9 +259,10 @@ public class ZF2PushTest extends TestCase {
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")
.setContact(new Contact("contact testname", "123456", "contact.testemail@example.org").setFax("0911623562")))
.setNumber(number)
.addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("AReason").setTaxPercent(new BigDecimal(19)))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addAllowance(new Allowance(new BigDecimal("0.1"))))
.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)).setReasonCode("ABK")))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(2.0)).addCharge(new Charge(new BigDecimal(1)).setReasonCode("ABK").setReason("AnotherReason")))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), amount, new BigDecimal(1.0)).addCharge(new Charge(new BigDecimal(1))).addAllowance(new Allowance(new BigDecimal("1"))))
);
@@ -280,7 +281,7 @@ public class ZF2PushTest extends TestCase {
assertTrue(zi.getUTF8().contains("ABK"));
// Reading ZUGFeRD
assertEquals("18.33", zi.getAmount());
assertEquals("19.52", zi.getAmount());
assertEquals(orgname, zi.getHolder());
assertEquals(number, zi.getForeignReference());
try {
@@ -530,7 +531,7 @@ public class ZF2PushTest extends TestCase {
try {
SchemedID gtin = new SchemedID("0160", "2001015001325");
SchemedID gln = new SchemedID("0088", "4304171000002");
ze.setTransaction(new Invoice().setCurrency("CHF").addNote("document level 1/2").addNote("document level 2/2").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
ze.setTransaction(new Invoice().setCurrency("CHF").addNote("document level 1/2").addNote("document level 2/2").setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setPaymentReference("Verwendungszweck").setDocumentName("Rechnung")
.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"))
@@ -582,6 +583,7 @@ public class ZF2PushTest extends TestCase {
assertTrue(zi.getUTF8().contains("++49555123456"));
assertTrue(zi.getUTF8().contains("Cash Discount")); // default description for cash discounts
assertThat(zi.getUTF8()).valueByXPath("//*[local-name()='ApplicableTradeTax']/*[local-name()='DueDateTypeCode']").asString().isEqualTo(EventTimeCodeTypeConstants.PAYMENT_DATE);
assertTrue(zi.getUTF8().contains("<ram:Name>Rechnung</ram:Name>"));
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(TARGET_PUSHEDGE);
try {
@@ -593,6 +595,8 @@ public class ZF2PushTest extends TestCase {
assertEquals("4304171000002", i.getRecipient().getGlobalID());
assertEquals("2001015001325", i.getZFItems()[0].getProduct().getGlobalID());
assertEquals(orgID, i.getSender().getID());
assertEquals("Verwendungszweck", i.getPaymentReference());
assertEquals("Rechnung", i.getDocumentName());
} catch (XPathExpressionException e) {
fail("XPathExpressionException should not be raised");

View File

@@ -233,6 +233,24 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
}
public void testSpecifiedLogisticsChargeImport() {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
File expectedResult = getResourceAsFile("cii/extended_warenrechnung.xml");
boolean hasExceptions = false;
CalculatedInvoice invoice = new CalculatedInvoice();
try {
zii.setInputStream(new FileInputStream(expectedResult));
zii.extractInto(invoice);
} catch (XPathExpressionException | ParseException | FileNotFoundException e) {
hasExceptions = true;
}
assertFalse(hasExceptions);
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("518.99"), tc.getGrandTotal());
}
public void testItemAllowancesChargesImport() {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushItemChargesAllowances.pdf");
@@ -246,7 +264,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
}
assertFalse(hasExceptions);
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("18.33"), tc.getGrandTotal());
assertEquals(new BigDecimal("19.52"), tc.getGrandTotal());
}
public void testBasisQuantityImport() {
@@ -265,6 +283,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
assertEquals(new BigDecimal("337.60"), tc.getGrandTotal());
}
public void testAllowancesChargesImport() {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushChargesAllowances.pdf");
@@ -306,7 +325,6 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
assertFalse(hasExceptions);
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("1.00"), tc.getGrandTotal());
@@ -315,6 +333,9 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
LineCalculator lc=new LineCalculator(invoice.getZFItems()[0]);
assertTrue(new BigDecimal("1").compareTo(lc.getItemTotalNetAmount()) == 0);
assertEquals("Z", invoice.getZFItems()[0].getProduct().getTaxCategoryCode());
assertEquals("Kleinunternehmer", invoice.getZFItems()[0].getProduct().getTaxExemptionReason());
assertTrue(invoice.getTradeSettlement().length == 1);
assertTrue(invoice.getTradeSettlement()[0] instanceof IZUGFeRDTradeSettlementPayment);
IZUGFeRDTradeSettlementPayment paym = (IZUGFeRDTradeSettlementPayment) invoice.getTradeSettlement()[0];
@@ -334,6 +355,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
byte[] fileA = null;
byte[] fileB = null;
boolean facturXFound=false;
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushAttachments.pdf");
for (FileAttachment fa : zii.getFileAttachmentsPDF()) {
@@ -341,24 +363,26 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
fileA = fa.getData();
} else if (fa.getFilename().equals("two.pdf")) {
fileB = fa.getData();
} else if (fa.getFilename().equals("factur-x.xml")) {
facturXFound=true;
}
}
byte[] b = {12, 13}; // the sample data that was used to write the files
assertTrue(facturXFound);
assertTrue(Arrays.equals(fileA, b));
assertEquals(fileA.length, 2);
assertTrue(Arrays.equals(fileB, b));
assertEquals(fileB.length, 2);
}
public void testImportDebit() {
File CIIinputFile = getResourceAsFile("cii/minimalDebit.xml");
try {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(CIIinputFile));
Invoice i = zii.extractInvoice();
assertEquals("DE21860000000086001055", i.getSender().getBankDetails().get(0).getIBAN());
assertEquals("DE21860000000086001055", i.getRecipient().getBankDetails().get(0).getIBAN());
ObjectMapper mapper = new ObjectMapper();
String jsonArray = mapper.writeValueAsString(i);

View File

@@ -0,0 +1,567 @@
<?xml version='1.0' encoding='UTF-8' ?>
<!-- English disclaimer below.-->
<!--Nutzungsrechte
ZUGFeRD Datenformat Version 2.2.0, 14.02.2022
Beispiel Version 14.02.2022
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.2.0, February 14th, 2022
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>R87654321012345</ram:ID>
<ram:Name>WARENRECHNUNG</ram:Name>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20180806</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 zu 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
WEEE-Reg-Nr.: DE87654321
</ram:Content>
<ram:SubjectCode>REG</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>Leergutwert: 46,50</ram:Content>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>Wichtige Information: Bei Bestellungen bis zum 19.12. ist die Auslieferung bis spätestens 23.12. garantiert.</ram:Content>
</ram:IncludedNote>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0160">4123456000014</ram:GlobalID>
<ram:SellerAssignedID>ZS997</ram:SellerAssignedID>
<ram:Name>Zitronensäure 100ml</ram:Name>
<ram:ApplicableProductCharacteristic>
<ram:Description>Verpackungsart</ram:Description>
<ram:Value>BO</ram:Value>
</ram:ApplicableProductCharacteristic>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>1.0000</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>1.0000</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">100.0000</ram:BilledQuantity>
<ram:PackageQuantity unitCode="XCT">4.0000</ram:PackageQuantity>
</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>100.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="0160">4123456000021</ram:GlobalID>
<ram:SellerAssignedID>GZ250</ram:SellerAssignedID>
<ram:Name>Gelierzucker Extra 250g</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>1.5000</ram:ChargeAmount>
<ram:AppliedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:ActualAmount>0.0300</ram:ActualAmount>
<ram:Reason>Artikelrabatt 1</ram:Reason>
</ram:AppliedTradeAllowanceCharge>
<ram:AppliedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:ActualAmount>0.0200</ram:ActualAmount>
<ram:Reason>Artikelrabatt 2</ram:Reason>
</ram:AppliedTradeAllowanceCharge>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>1.4500</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">50.0000</ram:BilledQuantity>
<ram:PackageQuantity unitCode="XCT">1.0000</ram:PackageQuantity>
</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>72.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="0160">4123456000021</ram:GlobalID>
<ram:SellerAssignedID>GZ250</ram:SellerAssignedID>
<ram:Name>Gelierzucker Extra 250g</ram:Name>
<ram:Description>Artikel wie vereinbart ohne Berechnung</ram:Description>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>0.0000</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>0.0000</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">10.0000</ram:BilledQuantity>
<ram:PackageQuantity unitCode="XCT">1.0000</ram:PackageQuantity>
</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>0.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>4</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0160">4100130013294</ram:GlobalID>
<ram:SellerAssignedID>2031</ram:SellerAssignedID>
<ram:BuyerAssignedID/>
<ram:Name>Bierbrau Pils 20/0500</ram:Name>
<ram:Description>EAN-VKE: 4100130913297</ram:Description>
<ram:ApplicableProductCharacteristic>
<ram:Description>Verpackung</ram:Description>
<ram:Value>Kiste</ram:Value>
</ram:ApplicableProductCharacteristic>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>12.0000</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>12.0000</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="XBC">15.0000</ram:BilledQuantity>
<ram:PackageQuantity unitCode="XBO">20.0000</ram:PackageQuantity>
</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>180.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>5</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0160">2001015001325</ram:GlobalID>
<ram:SellerAssignedID>1805</ram:SellerAssignedID>
<ram:BuyerAssignedID/>
<ram:Name>Leergutpfand 20 x 0,5l</ram:Name>
<ram:ApplicableProductCharacteristic>
<ram:Description>Verpackung</ram:Description>
<ram:Value>unverpackt</ram:Value>
</ram:ApplicableProductCharacteristic>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>3.1000</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>3.1000</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">15.0000</ram:BilledQuantity>
<ram:PackageQuantity unitCode="XBC">1.0000</ram:PackageQuantity>
</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>46.50</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>6</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0160">4123456000038</ram:GlobalID>
<ram:SellerAssignedID>MP107</ram:SellerAssignedID>
<ram:Name>Mischpalette Joghurt Karton 3 x 20</ram:Name>
<ram:ApplicableProductCharacteristic>
<ram:Description>Verpackung</ram:Description>
<ram:Value>Karton</ram:Value>
</ram:ApplicableProductCharacteristic>
<ram:IncludedReferencedProduct>
<ram:GlobalID schemeID="0160">4123456001035</ram:GlobalID>
<ram:SellerAssignedID>JOG103</ram:SellerAssignedID>
<ram:Name>Erdbeer 20 x 150g Becher</ram:Name>
<ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity>
</ram:IncludedReferencedProduct>
<ram:IncludedReferencedProduct>
<ram:GlobalID schemeID="0160">4123456002032</ram:GlobalID>
<ram:SellerAssignedID>JOG203</ram:SellerAssignedID>
<ram:Name>Banane 20 x 150g Becher</ram:Name>
<ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity>
</ram:IncludedReferencedProduct>
<ram:IncludedReferencedProduct>
<ram:GlobalID schemeID="0160">4123456003039</ram:GlobalID>
<ram:SellerAssignedID>JOG303</ram:SellerAssignedID>
<ram:Name>Schoko 20 x 150g Becher</ram:Name>
<ram:UnitQuantity unitCode="C62">20.0000</ram:UnitQuantity>
</ram:IncludedReferencedProduct>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>30.0000</ram:ChargeAmount>
<ram:AppliedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:ActualAmount>0.9000</ram:ActualAmount>
<ram:Reason>Artikelrabatt 1</ram:Reason>
</ram:AppliedTradeAllowanceCharge>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>29.1000</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">2.0000</ram:BilledQuantity>
<ram:PackageQuantity unitCode="XPX">1.0000</ram:PackageQuantity>
</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>58.20</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="VA">DE123456789</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:ID>009420</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:BuyerOrderReferencedDocument>
<ram:IssuerAssignedID>B123456789</ram:IssuerAssignedID>
</ram:BuyerOrderReferencedDocument>
<ram:AdditionalReferencedDocument>
<ram:IssuerAssignedID>A456123</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>8211</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">20180805</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
<ram:DeliveryNoteReferencedDocument>
<ram:IssuerAssignedID>L87654321012345</ram:IssuerAssignedID>
</ram:DeliveryNoteReferencedDocument>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:InvoiceeTradeParty>
<ram:ID>009420</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>61.07</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>321.40</ram:BasisAmount>
<ram:LineTotalBasisAmount>326.50</ram:LineTotalBasisAmount>
<ram:AllowanceChargeBasisAmount>-5.10</ram:AllowanceChargeBasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>8.93</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>127.59</ram:BasisAmount>
<ram:LineTotalBasisAmount>130.70</ram:LineTotalBasisAmount>
<ram:AllowanceChargeBasisAmount>-3.11</ram:AllowanceChargeBasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:CalculationPercent>2.00</ram:CalculationPercent>
<ram:BasisAmount>280.00</ram:BasisAmount>
<ram:ActualAmount>5.60</ram:ActualAmount>
<ram:Reason>Rechnungsrabatt 1</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:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:CalculationPercent>2.00</ram:CalculationPercent>
<ram:BasisAmount>130.70</ram:BasisAmount>
<ram:ActualAmount>2.61</ram:ActualAmount>
<ram:Reason>Rechnungsrabatt 1</ram:Reason>
<ram:CategoryTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:CategoryTradeTax>
</ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:BasisAmount>280.00</ram:BasisAmount>
<ram:ActualAmount>2.50</ram:ActualAmount>
<ram:Reason>Rechnungsrabatt 2</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:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:BasisAmount>130.70</ram:BasisAmount>
<ram:ActualAmount>0.50</ram:ActualAmount>
<ram:Reason>Rechnungsrabatt 2</ram:Reason>
<ram:CategoryTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:CategoryTradeTax>
</ram:SpecifiedTradeAllowanceCharge>
<ram:SpecifiedLogisticsServiceCharge>
<ram:Description>Transportkosten</ram:Description>
<ram:AppliedAmount>3.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>Bei Zahlung innerhalb 14 Tagen gewähren wir 2,0% Skonto.</ram:Description>
<ram:ApplicableTradePaymentDiscountTerms>
<ram:BasisPeriodMeasure unitCode="DAY">14</ram:BasisPeriodMeasure>
<ram:CalculationPercent>2.00</ram:CalculationPercent>
</ram:ApplicableTradePaymentDiscountTerms>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>457.20</ram:LineTotalAmount>
<ram:ChargeTotalAmount>3.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>11.21</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>448.99</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">70.00</ram:TaxTotalAmount>
<ram:GrandTotalAmount>518.99</ram:GrandTotalAmount>
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
<ram:DuePayableAmount>518.99</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>