Merge branch 'master' into feature/optimize_pom.xml_1

This commit is contained in:
Frank Langelage
2025-10-07 22:12:06 +02:00
committed by GitHub
30 changed files with 864 additions and 159 deletions

View File

@@ -1,3 +1,17 @@
- added JSONIgnore for Products intra community supply, reverse charge and invoice's isValid (which rather means isComplete, by the way)
- #917
- #915
- #921
- #926
- upgrade apache fop 2.10 to 2.11
- #931
- #932
- #933, #413, #557, #765
- make Line Calculation, e.g. total line net amount, accessible via JSON using getCalculation
- #940
- #939
- #692
2.19.0
=======
2025-08-12

View File

@@ -39,9 +39,8 @@ public class Allowance extends Charge {
return totalAmount;
} else if (percent!=null) {
BigDecimal singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100))));
// BigDecimal singlePrice=currentItem.getValue().multiply(BigDecimal.ONE.subtract(getPercent().divide(new BigDecimal(100))));
BigDecimal singlePriceDiff=currentItem.getValue().subtract(singlePrice);
return singlePriceDiff;
return singlePriceDiff.multiply(currentItem.getQuantity());
} else {
throw new RuntimeException("percent must be set");
}

View File

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

View File

@@ -10,7 +10,7 @@ public class FileAttachment {
protected String filename;
protected String mimetype;
protected String relation = "Unspecified";
protected String description;
protected String description = "Additional file attachment";
protected byte[] data;
@@ -21,19 +21,25 @@ public class FileAttachment {
}
public FileAttachment(String filename, String mimetype, String relation, byte[] data, String description) {
this.filename = filename;
this.mimetype = mimetype;
this.relation = relation;
this.data = data;
this.description = description;
}
public FileAttachment(String filename, String mimetype, String relation, byte[] data) {
this.filename = filename;
this.mimetype = mimetype;
this.relation = relation;
this.data = data;
this.description = "Additional file attachment";
}
public FileAttachment(String filename, String mimetype, byte[] data) {
this.filename = filename;
this.mimetype = mimetype;
this.data = data;
this.description = "Additional file attachment";
}
public String getDescription() {

View File

@@ -23,6 +23,7 @@ package org.mustangproject;
import java.math.BigDecimal;
import java.util.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.*;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
@@ -393,24 +394,29 @@ public class Invoice implements IExportableTransaction {
return this;
}
@JsonIgnore
@Override
public String getOwnStreet() {
return sender.getStreet();
}
@JsonIgnore
@Override
public String getOwnZIP() {
return sender.getZIP();
}
@JsonIgnore
@Override
public String getOwnLocation() {
return sender.getLocation();
}
@JsonIgnore
@Override
public String getOwnCountry() {
return sender.getCountry();
@@ -754,6 +760,7 @@ public class Invoice implements IExportableTransaction {
* checks if all required items are set in order to be able to export it
* @return true if all required items are set
*/
@JsonIgnore
public boolean isValid() {
return (dueDate != null) && (sender != null) && (sender.getTaxID() != null) && (sender.getVATID() != null) && (recipient != null);
//contact

View File

@@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import org.mustangproject.ZUGFeRD.IReferencedDocument;
import org.mustangproject.ZUGFeRD.IZUGFeRDAllowanceCharge;
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem;
import org.mustangproject.ZUGFeRD.LineCalculator;
import org.mustangproject.util.NodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@@ -203,9 +204,6 @@ public class Item implements IZUGFeRDExportableItem {
}
if (amountString != null) {
izac.setTotalAmount(new BigDecimal(amountString));
if (percentString != null && (!percentString.equals("0"))) {
izac.setTotalAmount(new BigDecimal(amountString).divide(getQuantity()));
}
}
if (basisAmountString != null) {
izac.setBasisAmount(new BigDecimal(basisAmountString));

View File

@@ -214,11 +214,14 @@ public class Product implements IZUGFeRDExportableProduct {
return this;
}
@JsonIgnore
@Override
public boolean isReverseCharge() {
return isReverseCharge;
}
@JsonIgnore
@Override
public boolean isIntraCommunitySupply() {
return isIntraCommunitySupply;

View File

@@ -40,5 +40,9 @@ public enum SubjectCode {
/**
* Vehicle licence number
*/
ABZ
ABZ,
/**
* Payment information
*/
PMT
}

View File

@@ -79,7 +79,7 @@ public class DAPullProvider extends ZUGFeRD2PullProvider {
if (currentItem.getProduct().getTaxExemptionReason() != null) {
// exemptionReason = "<ram:ExemptionReason>" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + "</ram:ExemptionReason>";
}
final LineCalculator lc = new LineCalculator(currentItem);
final LineCalculator lc = currentItem.getCalculation();
xml += "<ram:IncludedSupplyChainTradeLineItem>" +
"<ram:AssociatedDocumentLineDocument>"
+ "<ram:LineID>" + lineID + "</ram:LineID>"

View File

@@ -24,4 +24,7 @@ public interface IAbsoluteValueProvider {
public BigDecimal getValue();
default BigDecimal getQuantity() {
return BigDecimal.ONE;
}
}

View File

@@ -34,6 +34,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.mustangproject.FileAttachment;
import org.mustangproject.IncludedNote;
import org.mustangproject.ReferencedDocument;
@@ -181,6 +182,7 @@ public interface IExportableTransaction {
*
* @return Tax ID (not VAT ID) of the sender
*/
@JsonIgnore
default String getOwnTaxID() {
if (getSender() != null) {
return getSender().getTaxID();
@@ -194,6 +196,7 @@ public interface IExportableTransaction {
*
* @return VAT ID (Umsatzsteueridentifikationsnummer) of the sender
*/
@JsonIgnore
default String getOwnVATID() {
if (getSender() != null) {
return getSender().getVATID();

View File

@@ -205,4 +205,6 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
default String getAccountingReference() {
return null;
}
default LineCalculator getCalculation() {return new LineCalculator(this); };
}

View File

@@ -24,26 +24,17 @@ public class LineCalculator {
if (currentItem.getItemAllowances() != null) {
for (IZUGFeRDAllowanceCharge allowance : currentItem.getItemAllowances()) {
BigDecimal factor=BigDecimal.ONE;
BigDecimal singleAllowance=allowance.getTotalAmount(currentItem);
addItemAllowance(singleAllowance);
if ((allowance.getPercent()!=null)&&(allowance.getPercent().compareTo(BigDecimal.ZERO)!=0)) {
factor=currentItem.getQuantity();
}
addAllowanceItemTotal(singleAllowance.multiply(factor));
addAllowanceItemTotal(singleAllowance);
}
}
if (currentItem.getItemCharges() != null) {
for (IZUGFeRDAllowanceCharge charge : currentItem.getItemCharges()) {
BigDecimal factor=BigDecimal.ONE;
BigDecimal singleCharge=charge.getTotalAmount(currentItem);
addItemCharge(singleCharge);
if ((charge.getPercent()!=null)&&(charge.getPercent().compareTo(BigDecimal.ZERO)!=0)) {
factor=currentItem.getQuantity();
}
subtractAllowanceItemTotal(singleCharge.multiply(factor));
subtractAllowanceItemTotal(singleCharge);
}
}

View File

@@ -107,7 +107,7 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
// exemptionReason = "<ram:ExemptionReason>" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + "</ram:ExemptionReason>";
}
final LineCalculator lc = new LineCalculator(currentItem);
final LineCalculator lc = currentItem.getCalculation();
xml += "<ram:IncludedSupplyChainTradeLineItem>" +
"<ram:AssociatedDocumentLineDocument>"
+ "<ram:LineID>" + lineID + "</ram:LineID>"

View File

@@ -195,7 +195,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
percent = currentItem.getProduct().getVATPercent();
}
if (percent != null) {
LineCalculator lc = new LineCalculator(currentItem);
LineCalculator lc = currentItem.getCalculation();
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(),
currentItem.getProduct().getTaxCategoryCode(), vatDueDateTypeCode);
String reasonText = currentItem.getProduct().getTaxExemptionReason();
@@ -265,7 +265,7 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
if (percent != null)
{
final LineCalculator lc = new LineCalculator(currentItem);
final LineCalculator lc = currentItem.getCalculation();
final VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(),
currentItem.getProduct().getTaxCategoryCode(), vatDueDateTypeCode, percent);
final String reasonText = currentItem.getProduct().getTaxExemptionReason();

View File

@@ -344,7 +344,7 @@ public class ZUGFeRD1PullProvider extends ZUGFeRD2PullProvider {
}
final LineCalculator lc = new LineCalculator(currentItem);
final LineCalculator lc = currentItem.getCalculation();
xml += "<ram:IncludedSupplyChainTradeLineItem>" +
"<ram:AssociatedDocumentLineDocument>"
+ "<ram:LineID>" + lineID + "</ram:LineID>"

View File

@@ -415,7 +415,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if (currentItem.getId() != null) {
lineIDStr = currentItem.getId();
}
final LineCalculator lc = new LineCalculator(currentItem);
final LineCalculator lc = currentItem.getCalculation();
if ((getProfile() != Profiles.getByName("Minimum")) && (getProfile() != Profiles.getByName("BasicWL"))) {
xml += "<ram:IncludedSupplyChainTradeLineItem>" +
"<ram:AssociatedDocumentLineDocument>"

View File

@@ -8,21 +8,8 @@ import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
import org.mustangproject.Allowance;
import org.mustangproject.BankDetails;
import org.mustangproject.CalculatedInvoice;
import org.mustangproject.Charge;
import org.mustangproject.DirectDebit;
import org.mustangproject.EStandard;
import org.mustangproject.*;
import org.mustangproject.Exceptions.StructureException;
import org.mustangproject.FileAttachment;
import org.mustangproject.IncludedNote;
import org.mustangproject.Invoice;
import org.mustangproject.Item;
import org.mustangproject.ReferencedDocument;
import org.mustangproject.SchemedID;
import org.mustangproject.TradeParty;
import org.mustangproject.XMLTools;
import org.mustangproject.util.NodeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,6 +48,8 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -606,10 +595,12 @@ public class ZUGFeRDInvoiceImporter {
}
zpp.addNotes(includedNotes);
String rootNode = extractString("local-name(/*)");
String potentialCashDiscountTerms=null;
if (rootNode != null && Set.of("Invoice", "CreditNote").contains(rootNode)) {
// UBL...
// //*[local-name()="Invoice" or local-name()="CreditNote"]
number = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"ID\"]").trim();
potentialCashDiscountTerms = extractString("/*[local-name()=\"Invoice\" or local-name()=\"CreditNote\"]/*[local-name()=\"PaymentTerms\"]/*[local-name()=\"Note\"]").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.isEmpty()) {
@@ -623,6 +614,10 @@ public class ZUGFeRDInvoiceImporter {
if (!deliveryDt.isEmpty()) {
deliveryDate = parseDate(deliveryDt, "yyyy-MM-dd");
}
} else {
//CII
potentialCashDiscountTerms = extractString("//*[local-name()=\"SpecifiedTradePaymentTerms\"]/*[local-name()=\"Description\"]").trim();
}
String creditorReferenceID = extractString("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"CreditorReferenceID\"]").trim();//BT-90
@@ -994,6 +989,12 @@ public class ZUGFeRDInvoiceImporter {
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.getMimeDecoder().decode(XMLTools.trimOrNull(attachmentNodes.item(i))));
NodeList nl = attachmentNodes.item(i).getParentNode().getChildNodes();
for (int j = 0; j < nl.getLength(); j++) {
if (nl.item(j).getLocalName() != null && nl.item(j).getLocalName().equals("Name")) {
fa.setDescription(nl.item(j).getTextContent());
}
}
zpp.embedFileInXML(fa);
// filename = "Aufmass.png" mimeCode = "image/png"
//EmbeddedDocumentBinaryObject cbc:EmbeddedDocumentBinaryObject mimeCode="image/png" filename="Aufmass.png"
@@ -1121,6 +1122,63 @@ public class ZUGFeRDInvoiceImporter {
}
}
xpr = xpath.compile("//*[local-name()=\"SpecifiedTradePaymentTerms\"]/*[local-name()=\"ApplicableTradePaymentDiscountTerms\"]");// cash discounts, UBL unknown
NodeList cashdiscountNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < cashdiscountNodes.getLength(); i++) {
NodeList cashDiscountNodeChilds = cashdiscountNodes.item(i).getChildNodes();
String chargeAmount = null;
String taxPercent = null;
CashDiscount cd=new CashDiscount();
for (int cashDiscountChildIndex = 0; cashDiscountChildIndex < cashDiscountNodeChilds.getLength(); cashDiscountChildIndex++) {
Node currentNode=cashDiscountNodeChilds.item(cashDiscountChildIndex);
String chargeChildName = currentNode.getLocalName();
if (chargeChildName != null) {
if (chargeChildName.equals("BasisPeriodMeasure")) {
if (currentNode.getAttributes().getNamedItem("unitCode").getNodeValue().equals("DAY")) {
cd.setDays(Integer.valueOf(XMLTools.trimOrNull(currentNode)));
}
} else if (chargeChildName.equals("CalculationPercent")) {
cd.setPercent(new BigDecimal(XMLTools.trimOrNull(currentNode)));
}
}
//appliedAmount
//AppliedTradeTax
}
if ((cd.getPercent() != null)&&(cd.getDays() != null)) {
zpp.addCashDiscount(cd);
}
}
if ((potentialCashDiscountTerms!=null&&potentialCashDiscountTerms.length()>3)) {
for (String currentLine:potentialCashDiscountTerms.split("\\n")) {
if (currentLine.startsWith("#SKONTO#")) {
CashDiscount cd=new CashDiscount();
Pattern pattern = Pattern.compile("#TAGE=(.*?)#", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(currentLine);
boolean daysFound = matcher.find();
String days=matcher.group(1);
pattern = Pattern.compile("#PROZENT=(.*?)#", Pattern.CASE_INSENSITIVE);
matcher = pattern.matcher(currentLine);
boolean percentFound = matcher.find();
String percent=matcher.group(1);
if (daysFound&&percentFound) {
cd.setDays(Integer.valueOf(days));
cd.setPercent(new BigDecimal(percent));
zpp.addCashDiscount(cd);
} //else : could not parse skonto
/*
String percent=;
cd.setDays()
cd.setPercent()*/
}
}
}
TransactionCalculator tc = new TransactionCalculator(zpp);
String calculatedPayableTotal = tc.getDuePayable().toPlainString();
@@ -1140,7 +1198,7 @@ public class ZUGFeRDInvoiceImporter {
try {
moreDetails = " with tax basis " + tc.getTaxBasis() + " and with positions " + tc.getTotal() + " = "
+ Stream.of(tc.trans.getZFItems())
.map(item -> new LineCalculator(item).getItemTotalNetAmount().toPlainString())
.map(item -> item.getCalculation().getItemTotalNetAmount().toPlainString())
.collect(Collectors.joining(" + "));
} catch (Exception ignored) {
}

View File

@@ -194,7 +194,12 @@
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$field-mapping-identifier = 'xr:Payment_due_date'"><xsl:value-of select="format-date(xs:date(.), xrf:_('date-format'))"/></xsl:when>
<xsl:when test="$field-mapping-identifier = 'xr:Payment_due_date'">
<xsl:for-each select="tokenize(., ';')">
<xsl:value-of select="format-date(xs:date(.), xrf:_('date-format'))"/>
<xsl:if test="position() != last()">; </xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:otherwise><xsl:value-of select="."/></xsl:otherwise>
</xsl:choose>
</xsl:otherwise>

View File

@@ -5,12 +5,15 @@ import static java.math.BigDecimal.valueOf;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.xmlunit.assertj.XmlAssert.assertThat;
import org.junit.Test;
import org.mustangproject.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmlunit.builder.Input;
import javax.xml.transform.Source;
import javax.xml.xpath.XPathExpressionException;
import java.io.*;
import java.math.BigDecimal;
@@ -32,7 +35,7 @@ public class CalculationTest extends ResourceCase {
.setQuantity(TEN)
.setProduct(product);
final LineCalculator calculator = new LineCalculator(currentItem);
final LineCalculator calculator = currentItem.getCalculation();
assertEquals(valueOf(100).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
assertEquals(valueOf(1000).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
@@ -51,7 +54,7 @@ public class CalculationTest extends ResourceCase {
.setItemAllowances(new IZUGFeRDAllowanceCharge[]{allowance})
.setProduct(product);
final LineCalculator calculator = new LineCalculator(currentItem);
final LineCalculator calculator = currentItem.getCalculation();
assertEquals(valueOf(148.73).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
assertEquals(valueOf(1769.89).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
@@ -71,7 +74,7 @@ public class CalculationTest extends ResourceCase {
.setItemCharges(new IZUGFeRDAllowanceCharge[]{charge})
.setProduct(product);
final LineCalculator calculator = new LineCalculator(currentItem);
final LineCalculator calculator = currentItem.getCalculation();
assertEquals(valueOf(148.73).stripTrailingZeros(), calculator.getPrice().stripTrailingZeros());
assertEquals(valueOf(1799.63).stripTrailingZeros(), calculator.getItemTotalNetAmount().stripTrailingZeros());
@@ -110,13 +113,13 @@ public class CalculationTest extends ResourceCase {
product.addAllowance(new Allowance(new BigDecimal(1)));
item = new Item(product, new BigDecimal("9.50"), new BigDecimal(25));
item.addCharge(new Charge(new BigDecimal(10)).setReasonCode("ZZZ").setReason("Zuschlag"));
LineCalculator lc = new LineCalculator(item);
LineCalculator lc = item.getCalculation();
assertEquals(new BigDecimal("222.50"), lc.getItemTotalNetAmount());
invoice.addItem(item);
product = new Product("Paper", "", "H87", new BigDecimal(25));
item = new Item(product, new BigDecimal("4.50"), new BigDecimal(15));
item.addAllowance(new Allowance().setPercent(new BigDecimal(5)).setReasonCode("ZZZ").setReason("Zuschlag"));
lc = new LineCalculator(item);
lc = item.getCalculation();
assertEquals(new BigDecimal("64.12"), lc.getItemTotalNetAmount());
invoice.addItem(item);
invoice.addAllowance(new Allowance().setPercent(new BigDecimal(10)).setTaxPercent(new BigDecimal(25)).setReasonCode("ZZZ").setReason("Mengenrabatt"));
@@ -162,6 +165,40 @@ public class CalculationTest extends ResourceCase {
}
/* @Test
public void testRounding() {
/*** xml of official fx sample with allowances and charges
* 10x100 with 10% and 50€ item discount =850€
* +8,75 charges on document level=858,75, +19%VAT=1021,91
* prepaid 500->due payable=521,91
*
File inputCII = getResourceAsFile("EN16931_1_Teilrechnung_corrected.xml");
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
Invoice invoice = null;
zii.doIgnoreCalculationErrors();
boolean hasExceptions = false;
try {
zii.setInputStream(new FileInputStream(inputCII));
invoice = zii.extractInvoice();
} catch (XPathExpressionException | ParseException e) {
// handle Exceptions
hasExceptions = true;
} catch (FileNotFoundException e) {
hasExceptions = true;
}
assertFalse(hasExceptions);
// Reading ZUGFeRD
final TransactionCalculator calculator = new TransactionCalculator(invoice);
assertEquals(valueOf(147.59).stripTrailingZeros(), calculator.getDuePayable().stripTrailingZeros());
}
*/
@Test
public void testTotalCalculatorGrandTotalRounding() {
SimpleDateFormat sqlDate = new SimpleDateFormat("yyyy-MM-dd");
@@ -283,10 +320,76 @@ public class CalculationTest extends ResourceCase {
item.addAllowance(new Allowance().setPercent(new BigDecimal(10)).setTaxPercent(BigDecimal.ZERO));
invoice.addItem(item);
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
zf2p.setProfile(Profiles.getByName("XRechnung"));
zf2p.generateXML(invoice);
String theXML = new String(zf2p.getXML());
assertThat(theXML).valueByXPath("//*[local-name()='ActualAmount']")
.asString()
.isEqualTo("0.55");// test for issue #917
TransactionCalculator calculator = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("4.95"), calculator.getGrandTotal().stripTrailingZeros());
}
public void testSimpleItemPercentCharge() {
/***
* a product with net 1.10 and qty 5 and relative item allowance of 10% should return 5 as line and grand total
*/
SimpleDateFormat sqlDate = new SimpleDateFormat("yyyy-MM-dd");
Invoice invoice = new Invoice();
invoice.setDocumentName("Rechnung");
invoice.setNumber("777777");
try {
invoice.setIssueDate(sqlDate.parse("2020-12-31"));
invoice.setDetailedDeliveryPeriod(sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[0]), sqlDate.parse("2020-12-01 - 2020-12-31".split(" - ")[1]));
invoice.setDeliveryDate(sqlDate.parse("2020-12-31"));
invoice.setDueDate(sqlDate.parse("2021-01-15"));
} catch (Exception e) {
LOGGER.error("Failed to set dates", e);
}
TradeParty sender = new TradeParty("Maier GmbH", "Musterweg 5", "11111", "Testung", "DE");
sender.addVATID("DE2222222222");
invoice.setSender(sender);
/* trade party (recipient) */
TradeParty recipient = new TradeParty("Teston GmbH" + " " + "Zentrale" + " " + "", "Testweg 5", "11111", "Testung", "DE");
recipient.setID("111111");
recipient.addVATID("DE111111111");
invoice.setRecipient(recipient);
/* item */
Product product;
Item item;
product = new Product("AAA", "", "H87", BigDecimal.ZERO);
item = new Item(product, new BigDecimal("1.10"), new BigDecimal(5.00));
item.addCharge(new Charge().setPercent(new BigDecimal(10)).setTaxPercent(BigDecimal.ZERO));
invoice.addItem(item);
ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
zf2p.setProfile(Profiles.getByName("XRechnung"));
zf2p.generateXML(invoice);
String theXML = new String(zf2p.getXML());
assertThat(theXML).valueByXPath("//*[local-name()='ActualAmount']")
.asString()
.isEqualTo("0.55");// test for issue #917
TransactionCalculator calculator = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("6.05"), calculator.getGrandTotal().stripTrailingZeros());
}
public void testSimpleDocumentPercentCharge() {
String orgname = "Test company";
@@ -390,7 +493,7 @@ public class CalculationTest extends ResourceCase {
.setQuantity(BigDecimal.valueOf(31))
.setBasisQuantity(BigDecimal.valueOf(366))
.setProduct(product);
final LineCalculator calculator = new LineCalculator(currentItem);
final LineCalculator calculator = currentItem.getCalculation();
assertEquals(BigDecimal.valueOf(32.74), calculator.getItemTotalNetAmount());
}

View File

@@ -479,6 +479,20 @@ public class DeSerializationTest extends ResourceCase {
assertEquals("sender@test.org", fromJSON.getSender().getEmail());
}
public void testItemAbsoluteChargeFromJSON() throws JsonProcessingException {
String globalID = "4000001123452";
String globalIDScheme = "0088";
String json="{\"number\":\"471102\",\"currency\":\"EUR\",\"issueDate\":\"2018-03-04T00:00:00.000+01:00\",\"dueDate\":\"2018-03-04T00:00:00.000+01:00\",\"deliveryDate\":\"2018-03-04T00:00:00.000+01:00\",\"sender\":{\"name\":\"Lieferant GmbH\",\"zip\":\"80333\",\"street\":\"Lieferantenstraße 20\",\"location\":\"München\",\"country\":\"DE\",\"taxID\":\"201/113/40209\",\"vatID\":\"DE123456789\",\"globalID\":\"4000001123452\",\"globalIDScheme\":\"0088\"},\"recipient\":{\"name\":\"Kunden AG Mitte\",\"zip\":\"69876\",\"street\":\"Kundenstraße 15\",\"location\":\"Frankfurt\",\"country\":\"DE\"},\"zfitems\":[{\"price\":9.9,\"quantity\":20,\"product\":{\"unit\":\"H87\",\"name\":\"Trennblätter A4\",\"description\":\"\",\"vatpercent\":19,\"taxCategoryCode\":\"S\"},\"itemCharges\":[{\"totalAmount\":1,\"taxPercent\":19,\"reason\":\"Invoice line charge reason\",\"categoryCode\":\"S\"}]},{\"price\":5.5,\"quantity\":50,\"product\":{\"unit\":\"H87\",\"name\":\"Joghurt Banane\",\"description\":\"\",\"vatpercent\":7,\"taxCategoryCode\":\"S\"}}]}";
ObjectMapper mapper = new ObjectMapper();
Invoice fromJSON = mapper.readValue(json, Invoice.class);
assertEquals(globalID, fromJSON.getSender().getGlobalID());
assertEquals(globalIDScheme, fromJSON.getSender().getGlobalIDScheme());
TransactionCalculator tc=new TransactionCalculator(fromJSON);
assertEquals(new BigDecimal("531.06"), tc.getDuePayable());
}
public void testGrossFromJSON() throws JsonProcessingException {
String json="{ \"documentCode\": \"380\", \"number\": \"123\", \"currency\": \"EUR\", \"paymentTermDescription\": \"Please remit until 28.07.2025\", \"issueDate\": 1753653600000, \"dueDate\": 1753653600000, \"sender\": { \"name\": \"Test company\", \"zip\": \"55232\", \"street\": \"teststr\", \"location\": \"teststadt\", \"country\": \"DE\", \"taxID\": \"4711\", \"vatID\": \"DE0815\", \"vatid\": \"DE0815\" }, \"recipient\": { \"name\": \"Franz Müller\", \"zip\": \"55232\", \"street\": \"teststr.12\", \"location\": \"Entenhausen\", \"country\": \"DE\", \"contact\": { \"name\": \"contact testname\", \"phone\": \"123456\", \"email\": \"contact.testemail@example.org\", \"fax\": \"0911623562\" } }, \"totalPrepaidAmount\": 0.00, \"lineTotalAmount\": 29.00, \"duePayable\": 34.51, \"grandTotal\": 34.51, \"taxBasis\": 29.00, \"valid\": true, \"zfitems\": [ { \"price\": 3.0000, \"quantity\": 10.0000, \"basisQuantity\": 1.0000, \"id\": \"1\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"allowances\": [ { \"totalAmount\": 0.1000, \"categoryCode\": \"S\" } ], \"vatpercent\": 19.00, \"intraCommunitySupply\": false, \"reverseCharge\": false }, \"value\": 3.0000 } ], \"ownVATID\": \"DE0815\", \"ownTaxID\": \"4711\", \"ownLocation\": \"teststadt\", \"ownZIP\": \"55232\", \"ownCountry\": \"DE\", \"ownStreet\": \"teststr\"}";

View File

@@ -102,7 +102,7 @@ public class XRTest extends TestCase {
BigDecimal amount = new BigDecimal(amountStr);
byte[] b = {12, 13};
FileAttachment fe1 = new FileAttachment("one.pdf", "application/pdf", "Alternative", b);
FileAttachment fe1 = new FileAttachment("one.pdf", "application/pdf", "Alternative", b,"Beschreibung");
Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").setEmail("sender@example.com").addTaxID("DE4711").addVATID("DE0815").setContact(new Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new BankDetails("DE12500105170648489890", "COBADEFXXX").setAccountName("kontoInhaber")))
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setEmail("recipient@sample.org"))
@@ -158,7 +158,7 @@ public class XRTest extends TestCase {
assertEquals(attachedFiles.length, 1);
assertTrue(Arrays.equals(attachedFiles[0].getData(), b));
assertEquals("Beschreibung",attachedFiles[0].getDescription());
}

View File

@@ -35,7 +35,6 @@ import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -235,9 +234,9 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
}
public void testSpecifiedLogisticsChargeImport() {
public void testSpecifiedLogisticsChargeCashDiscountImport() {
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
File expectedResult = getResourceAsFile("cii/extended_warenrechnung.xml");
File expectedResult = getResourceAsFile("cii/extended_warenrechnung_based_doublecashdiscount.xml");
boolean hasExceptions = false;
@@ -249,9 +248,11 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
hasExceptions = true;
}
assertFalse(hasExceptions);
assertEquals(invoice.getCashDiscounts().length,2);
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("518.99"), tc.getGrandTotal());
}
public void testItemAllowancesChargesImport() {
@@ -347,10 +348,10 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("1.00"), tc.getGrandTotal());
assertEquals(invoice.getCashDiscounts().length,2);
assertEquals(version,2);
assertTrue(new BigDecimal("1").compareTo(invoice.getZFItems()[0].getQuantity()) == 0);
LineCalculator lc=new LineCalculator(invoice.getZFItems()[0]);
LineCalculator lc=invoice.getZFItems()[0].getCalculation();
assertTrue(new BigDecimal("1").compareTo(lc.getItemTotalNetAmount()) == 0);
assertEquals("Z", invoice.getZFItems()[0].getProduct().getTaxCategoryCode());
@@ -407,7 +408,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
ObjectMapper mapper = new ObjectMapper();
String jsonArray = mapper.writeValueAsString(i);
JSONAssert.assertEquals("{\"documentCode\":\"380\",\"number\":\"471102\",\"currency\":\"EUR\",\"paymentTermDescription\":\"Der Betrag in Höhe von EUR 529,87 wird am 20.03.2018 von Ihrem Konto per SEPA-Lastschrift eingezogen.\\n \",\"issueDate\":1520121600000,\"deliveryDate\":1520121600000,\"sender\":{\"name\":\"Lieferant GmbH\",\"zip\":\"80333\",\"street\":\"Lieferantenstraße 20\",\"location\":\"München\",\"country\":\"DE\",\"taxID\":\"201/113/40209\",\"vatID\":\"DE123456789\",\"debitDetails\":[{\"mandate\":\"REF A-123\",\"paymentMeansCode\":\"59\",\"paymentMeansInformation\":\"SEPA direct debit\",\"iban\":\"DE21860000000086001055\"}],\"vatid\":\"DE123456789\"},\"recipient\":{\"name\":\"Kunden AG Mitte\",\"zip\":\"69876\",\"street\":\"Kundenstraße 15\",\"location\":\"Frankfurt\",\"country\":\"DE\",\"bankDetails\":[{\"paymentMeansCode\":\"58\",\"paymentMeansInformation\":\"SEPA credit transfer\",\"iban\":\"DE21860000000086001055\"}]},\"totalPrepaidAmount\":0.00,\"creditorReferenceID\":\"DE98ZZZ09999999999\",\"valid\":false,\"zfitems\":[{\"price\":9.9000,\"quantity\":20.0000,\"basisQuantity\":1.0000,\"id\":\"1\",\"product\":{\"unit\":\"H87\",\"name\":\"Trennblätter A4\",\"taxCategoryCode\":\"S\",\"vatpercent\":19.00,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"value\":9.9000},{\"price\":5.5000,\"quantity\":50.0000,\"basisQuantity\":1.0000,\"id\":\"2\",\"product\":{\"unit\":\"H87\",\"name\":\"Joghurt Banane\",\"taxCategoryCode\":\"S\",\"vatpercent\":7.00,\"reverseCharge\":false,\"intraCommunitySupply\":false},\"value\":5.5000}],\"tradeSettlement\":[{\"mandate\":\"REF A-123\",\"paymentMeansCode\":\"59\",\"paymentMeansInformation\":\"SEPA direct debit\",\"iban\":\"DE21860000000086001055\"}],\"ownTaxID\":\"201/113/40209\",\"ownZIP\":\"80333\",\"ownCountry\":\"DE\",\"ownVATID\":\"DE123456789\",\"ownLocation\":\"München\",\"ownStreet\":\"Lieferantenstraße 20\"}",jsonArray,false);
JSONAssert.assertEquals("{\"documentCode\":\"380\",\"number\":\"471102\",\"currency\":\"EUR\",\"paymentTermDescription\":\"Der Betrag in Höhe von EUR 529,87 wird am 20.03.2018 von Ihrem Konto per SEPA-Lastschrift eingezogen.\\n \",\"issueDate\":1520121600000,\"deliveryDate\":1520121600000,\"sender\":{\"name\":\"Lieferant GmbH\",\"zip\":\"80333\",\"street\":\"Lieferantenstraße 20\",\"location\":\"München\",\"country\":\"DE\",\"taxID\":\"201/113/40209\",\"vatID\":\"DE123456789\",\"debitDetails\":[{\"mandate\":\"REF A-123\",\"paymentMeansCode\":\"59\",\"paymentMeansInformation\":\"SEPA direct debit\",\"iban\":\"DE21860000000086001055\"}],\"vatid\":\"DE123456789\"},\"recipient\":{\"name\":\"Kunden AG Mitte\",\"zip\":\"69876\",\"street\":\"Kundenstraße 15\",\"location\":\"Frankfurt\",\"country\":\"DE\",\"bankDetails\":[{\"paymentMeansCode\":\"58\",\"paymentMeansInformation\":\"SEPA credit transfer\",\"iban\":\"DE21860000000086001055\"}]},\"totalPrepaidAmount\":0.00,\"creditorReferenceID\":\"DE98ZZZ09999999999\",\"zfitems\":[{\"price\":9.9000,\"quantity\":20.0000,\"basisQuantity\":1.0000,\"id\":\"1\",\"product\":{\"unit\":\"H87\",\"name\":\"Trennblätter A4\",\"taxCategoryCode\":\"S\",\"vatpercent\":19.00},\"value\":9.9000},{\"price\":5.5000,\"quantity\":50.0000,\"basisQuantity\":1.0000,\"id\":\"2\",\"product\":{\"unit\":\"H87\",\"name\":\"Joghurt Banane\",\"taxCategoryCode\":\"S\",\"vatpercent\":7.00},\"value\":5.5000}],\"tradeSettlement\":[{\"mandate\":\"REF A-123\",\"paymentMeansCode\":\"59\",\"paymentMeansInformation\":\"SEPA direct debit\",\"iban\":\"DE21860000000086001055\"}]}",jsonArray,false);
} catch (IOException e) {
fail("IOException not expected");
@@ -439,7 +440,153 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
String expectedIssueDate= String.valueOf(morning.toInstant().getEpochSecond() *1000);
String expectedPaymentTermDesciption="Please remit until "+german.format(now);
JSONAssert.assertEquals("{ \"documentCode\": \"380\", \"number\": \"123\", \"currency\": \"EUR\", \"paymentTermDescription\": \""+expectedPaymentTermDesciption+"\", \"issueDate\": "+expectedIssueDate+", \"dueDate\": "+expectedDueDate+", \"sender\": { \"name\": \"Test company\", \"zip\": \"55232\", \"street\": \"teststr\", \"location\": \"teststadt\", \"country\": \"DE\", \"taxID\": \"4711\", \"vatID\": \"DE0815\", \"vatid\": \"DE0815\" }, \"recipient\": { \"name\": \"Franz Müller\", \"zip\": \"55232\", \"street\": \"teststr.12\", \"location\": \"Entenhausen\", \"country\": \"DE\", \"contact\": { \"name\": \"contact testname\", \"phone\": \"123456\", \"email\": \"contact.testemail@example.org\", \"fax\": \"0911623562\" } }, \"totalPrepaidAmount\": 0.00, \"valid\": true, \"zfitems\": [ { \"price\": 3.0000, \"quantity\": 1.0000, \"basisQuantity\": 1.0000, \"id\": \"1\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemAllowances\": [ { \"totalAmount\": 0.10, \"taxPercent\": 0, \"categoryCode\": \"S\" } ], \"value\": 3.0000 }, { \"price\": 3.0000, \"quantity\": 1.0000, \"basisQuantity\": 1.0000, \"id\": \"2\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemAllowances\": [ { \"percent\": 50.00, \"totalAmount\": 1.5, \"basisAmount\": 3.00, \"taxPercent\": 0, \"reason\": \"In love with salesperson\", \"categoryCode\": \"S\" } ], \"value\": 3.0000 }, { \"price\": 3.0000, \"quantity\": 2.0000, \"basisQuantity\": 1.0000, \"id\": \"3\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemCharges\": [ { \"totalAmount\": 1.00, \"taxPercent\": 0, \"reason\": \"AnotherReason\", \"categoryCode\": \"S\" } ], \"value\": 3.0000 }, { \"price\": 3.0000, \"quantity\": 1.0000, \"basisQuantity\": 1.0000, \"id\": \"4\", \"product\": { \"unit\": \"H87\", \"name\": \"Testprodukt\", \"taxCategoryCode\": \"S\", \"vatpercent\": 19.00, \"reverseCharge\": false, \"intraCommunitySupply\": false }, \"itemCharges\": [ { \"totalAmount\": 1.00, \"taxPercent\": 0, \"reason\": \"Yet another reason\", \"categoryCode\": \"S\" } ], \"itemAllowances\": [ { \"totalAmount\": 1.00, \"taxPercent\": 0, \"reason\": \"Something completely strange\", \"categoryCode\": \"S\" } ], \"value\": 3.0000 } ], \"ownCountry\": \"DE\", \"zfcharges\": [ { \"totalAmount\": 1.00, \"taxPercent\": 19.00, \"reason\": \"AReason\", \"reasonCode\": \"ABK\", \"categoryCode\": \"S\" } ], \"ownVATID\": \"DE0815\", \"ownStreet\": \"teststr\", \"ownTaxID\": \"4711\", \"ownLocation\": \"teststadt\", \"ownZIP\": \"55232\"}",jsonArray,true);
JSONAssert.assertEquals("{\n" +
" \"documentCode\" : \"380\",\n" +
" \"number\" : \"123\",\n" +
" \"currency\" : \"EUR\",\n" +
" \"paymentTermDescription\" : "+expectedPaymentTermDesciption+",\n" +
" \"issueDate\" : "+expectedIssueDate+",\n" +
" \"dueDate\" : "+expectedDueDate+",\n" +
" \"sender\" : {\n" +
" \"name\" : \"Test company\",\n" +
" \"zip\" : \"55232\",\n" +
" \"street\" : \"teststr\",\n" +
" \"location\" : \"teststadt\",\n" +
" \"country\" : \"DE\",\n" +
" \"taxID\" : \"4711\",\n" +
" \"vatID\" : \"DE0815\",\n" +
" \"vatid\" : \"DE0815\"\n" +
" },\n" +
" \"recipient\" : {\n" +
" \"name\" : \"Franz Müller\",\n" +
" \"zip\" : \"55232\",\n" +
" \"street\" : \"teststr.12\",\n" +
" \"location\" : \"Entenhausen\",\n" +
" \"country\" : \"DE\",\n" +
" \"contact\" : {\n" +
" \"name\" : \"contact testname\",\n" +
" \"phone\" : \"123456\",\n" +
" \"email\" : \"contact.testemail@example.org\",\n" +
" \"fax\" : \"0911623562\"\n" +
" }\n" +
" },\n" +
" \"totalPrepaidAmount\" : 0.0,\n" +
" \"zfitems\" : [ {\n" +
" \"price\" : 3.0,\n" +
" \"quantity\" : 1.0,\n" +
" \"basisQuantity\" : 1.0,\n" +
" \"id\" : \"1\",\n" +
" \"product\" : {\n" +
" \"unit\" : \"H87\",\n" +
" \"name\" : \"Testprodukt\",\n" +
" \"taxCategoryCode\" : \"S\",\n" +
" \"vatpercent\" : 19.0\n" +
" },\n" +
" \"itemAllowances\" : [ {\n" +
" \"totalAmount\" : 0.1,\n" +
" \"taxPercent\" : 0,\n" +
" \"categoryCode\" : \"S\"\n" +
" } ],\n" +
" \"value\" : 3.0,\n" +
" \"calculation\" : {\n" +
" \"price\" : 3.0,\n" +
" \"priceGross\" : 3.0,\n" +
" \"itemTotalNetAmount\" : 2.9,\n" +
" \"itemTotalVATAmount\" : 0.551,\n" +
" \"itemTotalGrossAmount\" : 2.9\n" +
" }\n" +
" }, {\n" +
" \"price\" : 3.0,\n" +
" \"quantity\" : 1.0,\n" +
" \"basisQuantity\" : 1.0,\n" +
" \"id\" : \"2\",\n" +
" \"product\" : {\n" +
" \"unit\" : \"H87\",\n" +
" \"name\" : \"Testprodukt\",\n" +
" \"taxCategoryCode\" : \"S\",\n" +
" \"vatpercent\" : 19.0\n" +
" },\n" +
" \"itemAllowances\" : [ {\n" +
" \"percent\" : 50.0,\n" +
" \"totalAmount\" : 1.5,\n" +
" \"basisAmount\" : 3.0,\n" +
" \"taxPercent\" : 0,\n" +
" \"reason\" : \"In love with salesperson\",\n" +
" \"categoryCode\" : \"S\"\n" +
" } ],\n" +
" \"value\" : 3.0,\n" +
" \"calculation\" : {\n" +
" \"price\" : 3.0,\n" +
" \"priceGross\" : 3.0,\n" +
" \"itemTotalNetAmount\" : 1.5,\n" +
" \"itemTotalVATAmount\" : 0.285,\n" +
" \"itemTotalGrossAmount\" : 1.5\n" +
" }\n" +
" }, {\n" +
" \"price\" : 3.0,\n" +
" \"quantity\" : 2.0,\n" +
" \"basisQuantity\" : 1.0,\n" +
" \"id\" : \"3\",\n" +
" \"product\" : {\n" +
" \"unit\" : \"H87\",\n" +
" \"name\" : \"Testprodukt\",\n" +
" \"taxCategoryCode\" : \"S\",\n" +
" \"vatpercent\" : 19.0\n" +
" },\n" +
" \"itemCharges\" : [ {\n" +
" \"totalAmount\" : 1.0,\n" +
" \"taxPercent\" : 0,\n" +
" \"reason\" : \"AnotherReason\",\n" +
" \"categoryCode\" : \"S\"\n" +
" } ],\n" +
" \"value\" : 3.0,\n" +
" \"calculation\" : {\n" +
" \"price\" : 3.0,\n" +
" \"priceGross\" : 3.0,\n" +
" \"itemTotalNetAmount\" : 7.0,\n" +
" \"itemTotalVATAmount\" : 1.33,\n" +
" \"itemTotalGrossAmount\" : 7.0\n" +
" }\n" +
" }, {\n" +
" \"price\" : 3.0,\n" +
" \"quantity\" : 1.0,\n" +
" \"basisQuantity\" : 1.0,\n" +
" \"id\" : \"4\",\n" +
" \"product\" : {\n" +
" \"unit\" : \"H87\",\n" +
" \"name\" : \"Testprodukt\",\n" +
" \"taxCategoryCode\" : \"S\",\n" +
" \"vatpercent\" : 19.0\n" +
" },\n" +
" \"itemAllowances\" : [ {\n" +
" \"totalAmount\" : 1.0,\n" +
" \"taxPercent\" : 0,\n" +
" \"reason\" : \"Something completely strange\",\n" +
" \"categoryCode\" : \"S\"\n" +
" } ],\n" +
" \"itemCharges\" : [ {\n" +
" \"totalAmount\" : 1.0,\n" +
" \"taxPercent\" : 0,\n" +
" \"reason\" : \"Yet another reason\",\n" +
" \"categoryCode\" : \"S\"\n" +
" } ],\n" +
" \"value\" : 3.0,\n" +
" \"calculation\" : {\n" +
" \"price\" : 3.0,\n" +
" \"priceGross\" : 3.0,\n" +
" \"itemTotalNetAmount\" : 3.0,\n" +
" \"itemTotalVATAmount\" : 0.57,\n" +
" \"itemTotalGrossAmount\" : 3.0\n" +
" }\n" +
" } ],\n" +
" \"zfcharges\" : [ {\n" +
" \"totalAmount\" : 1.0,\n" +
" \"taxPercent\" : 19.0,\n" +
" \"reason\" : \"AReason\",\n" +
" \"reasonCode\" : \"ABK\",\n" +
" \"categoryCode\" : \"S\"\n" +
" } ]\n" +
"}",jsonArray,true);
} catch (IOException e) {
fail("IOException not expected");
} catch (XPathExpressionException e) {

View File

@@ -0,0 +1,379 @@
<?xml version='1.0' encoding='UTF-8' ?>
<!--
English disclaimer below.
-->
<!--
Nutzungsrechte
ZUGFeRD Datenformat Version 2.3.3
Factur-X Version 1.07.3 07.05.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.fnfe-mpe.org/factur-x bzw. www.ferd-net.de/ZUGFeRD-Download
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 Version 2.3.3
Factur-X Version 1.07.3 07.05.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.fnfe-mpe.org/factur-x resp. www.ferd-net.de/ZUGFeRD-Download
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:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>471102</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20180605</udt:DateTimeString>
</ram:IssueDateTime>
<ram:IncludedNote>
<ram:Content>Rechnung gemäß Bestellung Nr. 2018-471331 vom 01.03.2018.</ram:Content>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>Es bestehen Rabatt- und Bonusvereinbarungen.</ram:Content>
<ram:SubjectCode>AAK</ram:SubjectCode>
</ram:IncludedNote>
<ram:IncludedNote>
<ram:Content>Lieferant GmbH
Lieferantenstraße 20
80333 München
Deutschland
Geschäftsführer: Hans Muster
Handelsregisternummer: H A 123
</ram:Content>
<ram:SubjectCode>REG</ram:SubjectCode>
</ram:IncludedNote>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
<ram:IncludedNote>
<ram:Content>Wir erlauben uns Ihnen folgende Positionen aus der Lieferung Nr. 2018-51112 in Rechnung zu stellen:</ram:Content>
</ram:IncludedNote>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0160">4012345001235</ram:GlobalID>
<ram:SellerAssignedID>KR3M</ram:SellerAssignedID>
<ram:BuyerAssignedID/>
<ram:Name>Kunstrasen grün 3m breit</ram:Name>
<ram:Description>300cm x 100 cm</ram:Description>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>4.0000</ram:ChargeAmount>
<ram:AppliedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:ActualAmount>0.6667</ram:ActualAmount>
</ram:AppliedTradeAllowanceCharge>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>3.3333</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="MTK">3.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>10.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>2</ram:LineID>
<ram:IncludedNote>
<ram:Content>Bestellt wurden 5 kg Schweinesteak. Mit dieser Rechnung werden nur die bereits gelieferten Steaks berechnet. Die noch offenen 4 kg Schweinesteak werden separat geliefert und berechnet.</ram:Content>
</ram:IncludedNote>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:GlobalID schemeID="0160">4000050986428</ram:GlobalID>
<ram:SellerAssignedID>SFK5</ram:SellerAssignedID>
<ram:BuyerAssignedID/>
<ram:Name>Schweinesteak</ram:Name>
<ram:Description>Schweinesteak aus Deutschland</ram:Description>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>5.5000</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>5.5000</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="KGM">1.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>5.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">4000001234561</ram:GlobalID>
<ram:SellerAssignedID>GTRWA5</ram:SellerAssignedID>
<ram:BuyerAssignedID/>
<ram:Name>Mineralwasser Medium
12 x 1,0l PET
</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>5.4900</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>5.4900</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">20.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>109.80</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">4000001234578</ram:GlobalID>
<ram:SellerAssignedID>PFA5</ram:SellerAssignedID>
<ram:BuyerAssignedID/>
<ram:Name>Pfand</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>2.7700</ram:ChargeAmount>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>2.7700</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="H87">20.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>55.46</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:ID>549910</ram:ID>
<ram:GlobalID schemeID="0088">4000001123452</ram:GlobalID>
<ram:Name>Lieferant GmbH</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>80333</ram:PostcodeCode>
<ram:LineOne>Lieferantenstraße 20</ram:LineOne>
<ram:CityName>München</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="FC">201/113/40209</ram:ID>
</ram:SpecifiedTaxRegistration>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE123456789</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:ID>GE2020211</ram:ID>
<ram:Name>Kunden AG Mitte</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>69876</ram:PostcodeCode>
<ram:LineOne>Kundenstraße 15</ram:LineOne>
<ram:CityName>Frankfurt</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
</ram:BuyerTradeParty>
<ram:BuyerOrderReferencedDocument>
<ram:IssuerAssignedID>2018-471331</ram:IssuerAssignedID>
</ram:BuyerOrderReferencedDocument>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20180603</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>7.91</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>113.03</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>12.25</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>64.46</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeAllowanceCharge>
<ram:ChargeIndicator>
<udt:Indicator>false</udt:Indicator>
</ram:ChargeIndicator>
<ram:BasisAmount>10.00</ram:BasisAmount>
<ram:ActualAmount>1.00</ram:ActualAmount>
<ram:Reason>Sondernachlass</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>115.30</ram:BasisAmount>
<ram:ActualAmount>8.07</ram:ActualAmount>
<ram:Reason>Sondernachlass</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>true</udt:Indicator>
</ram:ChargeIndicator>
<ram:BasisAmount>115.30</ram:BasisAmount>
<ram:ActualAmount>5.80</ram:ActualAmount>
<ram:Reason>Versandkosten</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:SpecifiedTradePaymentTerms>
<ram:Description>Zahlbar innerhalb 30 Tagen netto bis 04.07.2018, 3% Skonto innerhalb 10 Tagen bis 15.06.2018</ram:Description>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>180.70</ram:LineTotalAmount>
<ram:ChargeTotalAmount>5.80</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>9.07</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>177.43</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">20.16</ram:TaxTotalAmount>
<ram:GrandTotalAmount>197.59</ram:GrandTotalAmount>
<ram:TotalPrepaidAmount>50.00</ram:TotalPrepaidAmount>
<ram:DuePayableAmount>147.59</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>

View File

@@ -1,90 +1,4 @@
<?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>
@@ -545,13 +459,20 @@ WEEE-Reg-Nr.: DE87654321
<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: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:SpecifiedTradePaymentTerms>
<ram:Description>Bei Zahlung innerhalb 7 Tagen gewähren wir 1,0% Skonto.</ram:Description>
<ram:ApplicableTradePaymentDiscountTerms>
<ram:BasisPeriodMeasure unitCode="DAY">7</ram:BasisPeriodMeasure>
<ram:CalculationPercent>1.00</ram:CalculationPercent>
</ram:ApplicableTradePaymentDiscountTerms>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>457.20</ram:LineTotalAmount>
<ram:ChargeTotalAmount>3.00</ram:ChargeTotalAmount>

View File

@@ -14,6 +14,7 @@ public class ValidationContext {
private String profile = null;
private String signature = null;
private boolean isValid = true;
private boolean hasPDF = false;
protected Logger logger;
private String filename;
@@ -22,6 +23,14 @@ public class ValidationContext {
results = new Vector<>();
}
public void setHasPDF() {
hasPDF=true;
}
public boolean hasPDF() {
return hasPDF;
}
public void addResultItem(ValidationResultItem vr) throws IrrecoverableValidationError {
results.add(vr);

View File

@@ -374,6 +374,14 @@ public class XMLValidator extends Validator {
addUnsupportedProfileResultItem();
}
}
} else {
// no CII -> has to be UBL
if (context.hasPDF()) {
final ValidationResultItem vri = new ValidationResultItem(ESeverity.error, "Factur-X/ZUGFeRD and Order-X are always strictly CII only, no UBL allowed.").setSection(17)
.setPart(EPart.fx);
context.addResultItem(vri);
}
}
if (xsltFilename != null) {
@@ -536,12 +544,15 @@ public class XMLValidator extends Validator {
}
ESeverity severity;
Node failNode = currentFailNode.getAttributes().getNamedItem("flag");
String failVal = failNode == null ? null : failNode.getNodeValue();
if (defaultSeverity == ESeverity.notice) {
severity = defaultSeverity;
} else if (currentFailNode.getAttributes().getNamedItem("flag") != null
&& "warning".equals(currentFailNode.getAttributes().getNamedItem("flag").getNodeValue())) {
} else if ("warning".equals(failVal)) {
// the XR issues warnings with flag=warning
severity = ESeverity.warning;
} else if ("information".equals(failVal)) {
severity = ESeverity.notice;
} else {
severity = ESeverity.error;
}

View File

@@ -121,6 +121,7 @@ public class ZUGFeRDValidator {
// Avoid reading again from file
pdfv.setFilenameAndContents(contextFilename, content);
context.setHasPDF();
optionsRecognized = true;
finalStringResult.append("<pdf>");
try {

View File

@@ -202,7 +202,7 @@ public class ZUGFeRDValidatorTest extends ResourceCase {
assertThat(res).valueByXPath("count(//notice)")
.asInt()
.isEqualTo(0);
.isEqualTo(1);
assertThat(res).valueByXPath("/validation/summary/@status")
.asString()
.isEqualTo("valid");// expect to be valid because XR notices are, well, only notices
@@ -216,14 +216,14 @@ public class ZUGFeRDValidatorTest extends ResourceCase {
assertThat(res).valueByXPath("count(//error)")
.asInt()
.isEqualTo(5);
.isEqualTo(4);
assertThat(res).valueByXPath("count(//warning)")
.asInt()
.isEqualTo(1);
assertThat(res).valueByXPath("count(//notice)")
.asInt()
.isEqualTo(0); // 12 notices RE XRechnung 3.0
.isEqualTo(1); // 12 notices RE XRechnung 3.0
assertThat(res).valueByXPath("/validation/summary/@status")
.asString()
.isEqualTo("invalid");// expect to be valid

View File

@@ -102,6 +102,32 @@
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>Zeitlose Dienstleistung</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Zeitlose Dienstleistung</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>0.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="XPP">1</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>0.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:BuyerReference>04011000-12345-03</ram:BuyerReference>
<ram:SellerTradeParty>