Merge branch 'master' of github.com:ZUGFeRD/mustangproject
# Conflicts: # library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java
This commit is contained in:
@@ -116,6 +116,12 @@
|
|||||||
<groupId>org.dom4j</groupId>
|
<groupId>org.dom4j</groupId>
|
||||||
<artifactId>dom4j</artifactId>
|
<artifactId>dom4j</artifactId>
|
||||||
<version>2.1.4</version>
|
<version>2.1.4</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>*</groupId>
|
||||||
|
<artifactId>*</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- CII to UBL conversion -->
|
<!-- CII to UBL conversion -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ public class DirectDebit implements IZUGFeRDTradeSettlementDebit {
|
|||||||
* bean constructor
|
* bean constructor
|
||||||
*/
|
*/
|
||||||
public DirectDebit() {
|
public DirectDebit() {
|
||||||
|
this.IBAN = "";
|
||||||
|
this.mandate = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
@@ -46,8 +47,18 @@ public class DirectDebit implements IZUGFeRDTradeSettlementDebit {
|
|||||||
return this.IBAN;
|
return this.IBAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DirectDebit setIBAN(String iBAN) {
|
||||||
|
this.IBAN = iBAN;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMandate() {
|
public String getMandate() {
|
||||||
return this.mandate;
|
return this.mandate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DirectDebit setMandate(String mandate) {
|
||||||
|
this.mandate = mandate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class FileAttachment {
|
|||||||
this.mimetype = mimetype;
|
this.mimetype = mimetype;
|
||||||
this.relation = relation;
|
this.relation = relation;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
description = "Additional file attachment";
|
this.description = "Additional file attachment";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
@@ -73,8 +73,4 @@ public class FileAttachment {
|
|||||||
this.data = data;
|
this.data = data;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,72 +9,77 @@ import com.fasterxml.jackson.annotation.JsonInclude;
|
|||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
public class IncludedNote {
|
public class IncludedNote {
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
private SubjectCode subjectCode;
|
private SubjectCode subjectCode;
|
||||||
|
|
||||||
private static final String INCLUDE_START = "<ram:IncludedNote>";
|
private static final String INCLUDE_START = "<ram:IncludedNote>";
|
||||||
private static final String INCLUDE_END = "</ram:IncludedNote>";
|
private static final String INCLUDE_END = "</ram:IncludedNote>";
|
||||||
private static final String CONTENT_START = "<ram:Content>";
|
private static final String CONTENT_START = "<ram:Content>";
|
||||||
private static final String CONTENT_END = "</ram:Content>";
|
private static final String CONTENT_END = "</ram:Content>";
|
||||||
private static final String SUBJECT_CODE_START = "<ram:SubjectCode>";
|
private static final String SUBJECT_CODE_START = "<ram:SubjectCode>";
|
||||||
private static final String SUBJECT_CODE_END = "</ram:SubjectCode>";
|
private static final String SUBJECT_CODE_END = "</ram:SubjectCode>";
|
||||||
|
|
||||||
private IncludedNote(String content, SubjectCode subjectCode) {
|
public IncludedNote(String content, SubjectCode subjectCode) {
|
||||||
this.content = content;
|
this.content = content;
|
||||||
this.subjectCode = subjectCode;
|
this.subjectCode = subjectCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bean constructor
|
* bean constructor
|
||||||
*/
|
*/
|
||||||
public IncludedNote() {
|
public IncludedNote() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IncludedNote generalNote(String content) {
|
public static IncludedNote generalNote(String content) {
|
||||||
return new IncludedNote(content, SubjectCode.AAI);
|
return new IncludedNote(content, SubjectCode.AAI);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IncludedNote regulatoryNote(String content) {
|
public static IncludedNote regulatoryNote(String content) {
|
||||||
return new IncludedNote(content, SubjectCode.REG);
|
return new IncludedNote(content, SubjectCode.REG);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IncludedNote legalNote(String content) {
|
public static IncludedNote legalNote(String content) {
|
||||||
return new IncludedNote(content, SubjectCode.ABL);
|
return new IncludedNote(content, SubjectCode.ABL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IncludedNote customsNote(String content) {
|
public static IncludedNote customsNote(String content) {
|
||||||
return new IncludedNote(content, SubjectCode.CUS);
|
return new IncludedNote(content, SubjectCode.CUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IncludedNote sellerNote(String content) {
|
public static IncludedNote sellerNote(String content) {
|
||||||
return new IncludedNote(content, SubjectCode.SUR);
|
return new IncludedNote(content, SubjectCode.SUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IncludedNote taxNote(String content) {
|
public static IncludedNote taxNote(String content) {
|
||||||
return new IncludedNote(content, SubjectCode.TXD);
|
return new IncludedNote(content, SubjectCode.TXD);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IncludedNote introductionNote(String content) {
|
public static IncludedNote introductionNote(String content) {
|
||||||
return new IncludedNote(content, SubjectCode.ACY);
|
return new IncludedNote(content, SubjectCode.ACY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IncludedNote discountBonusNote(String content) {
|
public static IncludedNote discountBonusNote(String content) {
|
||||||
return new IncludedNote(content, SubjectCode.AAK);
|
return new IncludedNote(content, SubjectCode.AAK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IncludedNote unspecifiedNote(String content) {
|
public static IncludedNote unspecifiedNote(String content) {
|
||||||
return new IncludedNote(content, null);
|
return new IncludedNote(content, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getContent() {
|
public String getContent() {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubjectCode getSubjectCode() {
|
public IncludedNote setContent(String content) {
|
||||||
return subjectCode;
|
this.content = content;
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubjectCode getSubjectCode() {
|
||||||
|
return subjectCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public IncludedNote setSubjectCode(SubjectCode subjectCode) {
|
public IncludedNote setSubjectCode(SubjectCode subjectCode) {
|
||||||
@@ -88,13 +93,13 @@ public class IncludedNote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String toCiiXml() {
|
public String toCiiXml(){
|
||||||
String result = INCLUDE_START + CONTENT_START +
|
String result = INCLUDE_START + CONTENT_START +
|
||||||
XMLTools.encodeXML(getContent()) + CONTENT_END;
|
XMLTools.encodeXML(getContent() )+ CONTENT_END;
|
||||||
if (getSubjectCode() != null) {
|
if (getSubjectCode() != null) {
|
||||||
result += SUBJECT_CODE_START + getSubjectCode() + SUBJECT_CODE_END;
|
result += SUBJECT_CODE_START + getSubjectCode() + SUBJECT_CODE_END;
|
||||||
}
|
}
|
||||||
return result + INCLUDE_END;
|
return result + INCLUDE_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ import org.w3c.dom.NodeList;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -39,6 +41,7 @@ public class Item implements IZUGFeRDExportableItem {
|
|||||||
protected ArrayList<ReferencedDocument> additionalReference = null;
|
protected ArrayList<ReferencedDocument> additionalReference = null;
|
||||||
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>();
|
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>();
|
||||||
protected ArrayList<IZUGFeRDAllowanceCharge> Charges = new ArrayList<>();
|
protected ArrayList<IZUGFeRDAllowanceCharge> Charges = new ArrayList<>();
|
||||||
|
protected List<IncludedNote> includedNotes = null;
|
||||||
//protected HashMap<String, String> attributes = new HashMap<>();
|
//protected HashMap<String, String> attributes = new HashMap<>();
|
||||||
|
|
||||||
/***
|
/***
|
||||||
@@ -124,6 +127,12 @@ public class Item implements IZUGFeRDExportableItem {
|
|||||||
.flatMap(bordNodes -> bordNodes.getAsString("LineID"))
|
.flatMap(bordNodes -> bordNodes.getAsString("LineID"))
|
||||||
.ifPresent(this::addReferencedLineID);
|
.ifPresent(this::addReferencedLineID);
|
||||||
|
|
||||||
|
itemMap.getAsString("ID")
|
||||||
|
.ifPresent(this::setId);
|
||||||
|
|
||||||
|
|
||||||
|
itemMap.getAsString("Note")
|
||||||
|
.ifPresent(this::addNote);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -172,6 +181,38 @@ public class Item implements IZUGFeRDExportableItem {
|
|||||||
|
|
||||||
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).forEach(this::addAdditionalReference);
|
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).forEach(this::addAdditionalReference);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itemMap.getAsString("Note").ifPresent(this::addNote);
|
||||||
|
itemMap.getAsNodeMap("AssociatedDocumentLineDocument").ifPresent(adld -> {
|
||||||
|
List<IncludedNote> includedNotes = new ArrayList<>();
|
||||||
|
adld.getAllNodes("IncludedNote").forEach(item -> {
|
||||||
|
String subjectCode = "";
|
||||||
|
String content = null;
|
||||||
|
NodeList includedNodeChilds = item.getChildNodes();
|
||||||
|
for (int issueDateChildIndex = 0; issueDateChildIndex < includedNodeChilds.getLength(); issueDateChildIndex++) {
|
||||||
|
if ((includedNodeChilds.item(issueDateChildIndex).getLocalName() != null)
|
||||||
|
&& (includedNodeChilds.item(issueDateChildIndex).getLocalName().equals("Content"))) {
|
||||||
|
content = XMLTools.trimOrNull(includedNodeChilds.item(issueDateChildIndex));
|
||||||
|
}
|
||||||
|
if ((includedNodeChilds.item(issueDateChildIndex).getLocalName() != null)
|
||||||
|
&& (includedNodeChilds.item(issueDateChildIndex).getLocalName().equals("SubjectCode"))) {
|
||||||
|
subjectCode = XMLTools.trimOrNull(includedNodeChilds.item(issueDateChildIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean foundCode = false;
|
||||||
|
for (SubjectCode code : SubjectCode.values()) {
|
||||||
|
if (code.toString().equals(subjectCode)) {
|
||||||
|
includedNotes.add(new IncludedNote(content, code));
|
||||||
|
foundCode = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundCode) {
|
||||||
|
includedNotes.add(new IncludedNote(content, null));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
addNotes(includedNotes);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Item addReferencedLineID(String s) {
|
public Item addReferencedLineID(String s) {
|
||||||
@@ -419,4 +460,19 @@ public class Item implements IZUGFeRDExportableItem {
|
|||||||
return detailedDeliveryPeriodTo;
|
return detailedDeliveryPeriodTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IZUGFeRDExportableItem addNotes(Collection<IncludedNote> notes) {
|
||||||
|
if (notes == null) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if (includedNotes == null) {
|
||||||
|
includedNotes = new ArrayList<>();
|
||||||
|
}
|
||||||
|
includedNotes.addAll(notes);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<IncludedNote> getNotesWithSubjectCode() {
|
||||||
|
return includedNotes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,5 +36,9 @@ public enum SubjectCode {
|
|||||||
/**
|
/**
|
||||||
* Discount and bonus agreements
|
* Discount and bonus agreements
|
||||||
*/
|
*/
|
||||||
AAK
|
AAK,
|
||||||
|
/**
|
||||||
|
* Vehicle licence number
|
||||||
|
*/
|
||||||
|
ABZ
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ package org.mustangproject.ZUGFeRD;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mustangproject.IncludedNote;
|
||||||
import org.mustangproject.Item;
|
import org.mustangproject.Item;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
@@ -153,7 +155,6 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
*
|
*
|
||||||
* @return the line ID
|
* @return the line ID
|
||||||
@@ -161,4 +162,14 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
|
|||||||
default String getId() {
|
default String getId() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A grouping of business terms to indicate accounting-relevant free texts including a qualification of these.
|
||||||
|
*
|
||||||
|
* The information are written to the same xml nodes like {@link #getNotes()} but with explicit subjectCode.
|
||||||
|
* @return list of the notes
|
||||||
|
*/
|
||||||
|
default List<IncludedNote> getNotesWithSubjectCode() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,10 +50,14 @@ public class LineCalculator {
|
|||||||
quantity=currentItem.getQuantity();
|
quantity=currentItem.getQuantity();
|
||||||
}
|
}
|
||||||
|
|
||||||
itemTotalNetAmount = quantity.multiply(getPrice()).divide(currentItem.getBasisQuantity(), 18, RoundingMode.HALF_UP)
|
// Division/Zero occurred here.
|
||||||
|
// Used the setScale only because that's also done in getBasisQuantity
|
||||||
|
BigDecimal basisQuantity = currentItem.getBasisQuantity().compareTo(BigDecimal.ZERO) == 0
|
||||||
|
? BigDecimal.ONE.setScale(4)
|
||||||
|
: currentItem.getBasisQuantity();
|
||||||
|
itemTotalNetAmount = quantity.multiply(getPrice()).divide(basisQuantity, 18, RoundingMode.HALF_UP)
|
||||||
.subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
|
.subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP);
|
||||||
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);
|
itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getPrice() {
|
public BigDecimal getPrice() {
|
||||||
|
|||||||
@@ -743,6 +743,15 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter {
|
|||||||
node = getNodeByName(node.getChildNodes(), "CalculatedAmount");
|
node = getNodeByName(node.getChildNodes(), "CalculatedAmount");
|
||||||
lineItem.setTax(XMLTools.tryBigDecimal(node));
|
lineItem.setTax(XMLTools.tryBigDecimal(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node = getNodeByName(nn.getChildNodes(), "ApplicableTradeTax");
|
||||||
|
if (node != null) {
|
||||||
|
node = getNodeByName(node.getChildNodes(), "CategoryCode");
|
||||||
|
if(node != null){
|
||||||
|
lineItem.getProduct().setTaxCategoryCode(XMLTools.getNodeValue(node));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
node = getNodeByName(nn.getChildNodes(), "BillingSpecifiedPeriod");
|
node = getNodeByName(nn.getChildNodes(), "BillingSpecifiedPeriod");
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
final Node start = getNodeByName(node.getChildNodes(), "StartDateTime");
|
final Node start = getNodeByName(node.getChildNodes(), "StartDateTime");
|
||||||
|
|||||||
@@ -327,8 +327,10 @@ public class ZUGFeRDInvoiceImporter {
|
|||||||
deliveryLocationNodeMap -> {
|
deliveryLocationNodeMap -> {
|
||||||
|
|
||||||
deliveryLocationNodeMap.getNode("ID").ifPresent(s -> {
|
deliveryLocationNodeMap.getNode("ID").ifPresent(s -> {
|
||||||
SchemedID sID = new SchemedID().setScheme(s.getAttributes().getNamedItem("schemeID").getTextContent()).setId(s.getTextContent());
|
if (s.getAttributes().getNamedItem("schemeID") != null) {
|
||||||
delivery.addGlobalID(sID);
|
SchemedID sID = new SchemedID().setScheme(s.getAttributes().getNamedItem("schemeID").getTextContent()).setId(s.getTextContent());
|
||||||
|
delivery.addGlobalID(sID);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
|
deliveryLocationNodeMap.getAsNodeMap("Address").ifPresent(s -> {
|
||||||
s.getAsString("StreetName").ifPresent(t -> delivery.setStreet(t));
|
s.getAsString("StreetName").ifPresent(t -> delivery.setStreet(t));
|
||||||
|
|||||||
@@ -22,12 +22,15 @@ package org.mustangproject.ZUGFeRD;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.StringUtils;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mustangproject.*;
|
import org.mustangproject.*;
|
||||||
|
|
||||||
import javax.xml.xpath.XPathExpressionException;
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -308,7 +311,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
|||||||
LineCalculator lc=new LineCalculator(invoice.getZFItems()[0]);
|
LineCalculator lc=new LineCalculator(invoice.getZFItems()[0]);
|
||||||
assertTrue(new BigDecimal("1").compareTo(lc.getItemTotalNetAmount()) == 0);
|
assertTrue(new BigDecimal("1").compareTo(lc.getItemTotalNetAmount()) == 0);
|
||||||
|
|
||||||
assertTrue(invoice.getTradeSettlement().length==1);
|
assertTrue(invoice.getTradeSettlement().length == 1);
|
||||||
assertTrue(invoice.getTradeSettlement()[0] instanceof IZUGFeRDTradeSettlementPayment);
|
assertTrue(invoice.getTradeSettlement()[0] instanceof IZUGFeRDTradeSettlementPayment);
|
||||||
IZUGFeRDTradeSettlementPayment paym = (IZUGFeRDTradeSettlementPayment) invoice.getTradeSettlement()[0];
|
IZUGFeRDTradeSettlementPayment paym = (IZUGFeRDTradeSettlementPayment) invoice.getTradeSettlement()[0];
|
||||||
assertEquals("DE12500105170648489890", paym.getOwnIBAN());
|
assertEquals("DE12500105170648489890", paym.getOwnIBAN());
|
||||||
@@ -439,4 +442,25 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImportPositionIncludedNotes() throws FileNotFoundException, XPathExpressionException, ParseException {
|
||||||
|
File inputFile = getResourceAsFile("ZTESTZUGFERD_1_INVDSS_012015738820PDF-1.pdf");
|
||||||
|
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(inputFile));
|
||||||
|
|
||||||
|
Invoice invoice = zii.extractInvoice();
|
||||||
|
assertEquals(1, invoice.getZFItems().length);
|
||||||
|
assertEquals(8, invoice.getZFItems()[0].getNotesWithSubjectCode().size());
|
||||||
|
assertEquals("FB-LE 9999", invoice.getZFItems()[0].getNotesWithSubjectCode().stream().filter(note -> note.getSubjectCode().equals(SubjectCode.ABZ)).findFirst().get().getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImportXRechnungPositionNote() throws FileNotFoundException, XPathExpressionException, ParseException {
|
||||||
|
File inputFile = getResourceAsFile("TESTXRECHNUNG_INVDSS_012015776085.XML");
|
||||||
|
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(inputFile));
|
||||||
|
|
||||||
|
Invoice invoice = zii.extractInvoice();
|
||||||
|
assertEquals(1, invoice.getZFItems().length);
|
||||||
|
assertFalse(invoice.getZFItems()[0].getNotes() == null);
|
||||||
|
assertEquals(1, invoice.getZFItems()[0].getNotes().length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
157
library/src/test/resources/TESTXRECHNUNG_INVDSS_012015776085.XML
Normal file
157
library/src/test/resources/TESTXRECHNUNG_INVDSS_012015776085.XML
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?><ubl:Invoice xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2 http://docs.oasis-open.org/ubl/os-UBL-2.1/xsd/maindoc/UBL-Invoice-2.1.xsd">
|
||||||
|
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID>
|
||||||
|
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
|
||||||
|
<cbc:ID>2015776085</cbc:ID>
|
||||||
|
<cbc:IssueDate>2024-11-01</cbc:IssueDate>
|
||||||
|
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
|
||||||
|
<cbc:Note>#AAI# Wenn bereits bezahlt, nur zu den Akten legen. Für Verzug und Verzugszinsen gelten die Bestimmungen der §§ 286 - 288 BGB. Der Schuldner einer Entgeltforderung kommt spätestens in Verzug, wenn er nicht innerhalb von 30 Tagen nach Fälligkeit und Zugang einer Rechnung oder gleichwertigen Zahlungsaufstellung leistet. Die Lieferung von Waren und Fahrzeugen erfolgt unter Eigentumsvorbehalt.</cbc:Note>
|
||||||
|
<cbc:Note>#PAI# Rechnungsbetrag zahlbar ohne Abzug sofort nach Erhalt der Rechnung.</cbc:Note>
|
||||||
|
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
|
||||||
|
<cbc:BuyerReference>02-ZZ987654-99</cbc:BuyerReference>
|
||||||
|
<cac:InvoicePeriod>
|
||||||
|
<cbc:StartDate>2024-11-01</cbc:StartDate>
|
||||||
|
<cbc:EndDate>2024-11-30</cbc:EndDate>
|
||||||
|
</cac:InvoicePeriod>
|
||||||
|
<cac:OrderReference>
|
||||||
|
<cbc:ID>N/A</cbc:ID>
|
||||||
|
</cac:OrderReference>
|
||||||
|
<cac:ContractDocumentReference>
|
||||||
|
<cbc:ID>63435555</cbc:ID>
|
||||||
|
</cac:ContractDocumentReference>
|
||||||
|
<cac:AccountingSupplierParty>
|
||||||
|
<cac:Party>
|
||||||
|
<cbc:EndpointID schemeID="9930">DE238574172</cbc:EndpointID>
|
||||||
|
<cac:PartyName>
|
||||||
|
<cbc:Name>Alphabet Fuhrparkmanagement GmbH</cbc:Name>
|
||||||
|
</cac:PartyName>
|
||||||
|
<cac:PostalAddress>
|
||||||
|
<cbc:StreetName>Lilienthalallee 26</cbc:StreetName>
|
||||||
|
<cbc:CityName>München</cbc:CityName>
|
||||||
|
<cbc:PostalZone>80786</cbc:PostalZone>
|
||||||
|
<cac:Country>
|
||||||
|
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
|
||||||
|
</cac:Country>
|
||||||
|
</cac:PostalAddress>
|
||||||
|
<cac:PartyTaxScheme>
|
||||||
|
<cbc:CompanyID>DE238574172</cbc:CompanyID>
|
||||||
|
<cac:TaxScheme>
|
||||||
|
<cbc:ID>VAT</cbc:ID>
|
||||||
|
</cac:TaxScheme>
|
||||||
|
</cac:PartyTaxScheme>
|
||||||
|
<cac:PartyLegalEntity>
|
||||||
|
<cbc:RegistrationName>Alphabet Fuhrparkmanagement GmbH</cbc:RegistrationName>
|
||||||
|
<cbc:CompanyID>HRB 181098</cbc:CompanyID>
|
||||||
|
</cac:PartyLegalEntity>
|
||||||
|
<cac:Contact>
|
||||||
|
<cbc:Name>Yildiz Tolga</cbc:Name>
|
||||||
|
<cbc:Telephone>+49899--</cbc:Telephone>
|
||||||
|
<cbc:ElectronicMail>Tolga.Yildiz@alphabet.de</cbc:ElectronicMail>
|
||||||
|
</cac:Contact>
|
||||||
|
</cac:Party>
|
||||||
|
</cac:AccountingSupplierParty>
|
||||||
|
<cac:AccountingCustomerParty>
|
||||||
|
<cac:Party>
|
||||||
|
<cbc:EndpointID schemeID="9930">N/A</cbc:EndpointID>
|
||||||
|
<cac:PartyIdentification>
|
||||||
|
<cbc:ID>00987654</cbc:ID>
|
||||||
|
</cac:PartyIdentification>
|
||||||
|
<cac:PartyName>
|
||||||
|
<cbc:Name>Muster GmbH</cbc:Name>
|
||||||
|
</cac:PartyName>
|
||||||
|
<cac:PostalAddress>
|
||||||
|
<cbc:StreetName>Musterweg 1</cbc:StreetName>
|
||||||
|
<cbc:CityName>Kiel</cbc:CityName>
|
||||||
|
<cbc:PostalZone>24105</cbc:PostalZone>
|
||||||
|
<cac:Country>
|
||||||
|
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
|
||||||
|
</cac:Country>
|
||||||
|
</cac:PostalAddress>
|
||||||
|
<cac:PartyLegalEntity>
|
||||||
|
<cbc:RegistrationName>Muster GmbH</cbc:RegistrationName>
|
||||||
|
</cac:PartyLegalEntity>
|
||||||
|
<cac:Contact>
|
||||||
|
<cbc:Name>Mustermann Max</cbc:Name>
|
||||||
|
</cac:Contact>
|
||||||
|
</cac:Party>
|
||||||
|
</cac:AccountingCustomerParty>
|
||||||
|
<cac:Delivery>
|
||||||
|
<cbc:ActualDeliveryDate>2024-11-30</cbc:ActualDeliveryDate>
|
||||||
|
<cac:DeliveryLocation>
|
||||||
|
<cbc:ID>00987654</cbc:ID>
|
||||||
|
<cac:Address>
|
||||||
|
<cbc:StreetName>Musterweg 1</cbc:StreetName>
|
||||||
|
<cbc:CityName>Kiel</cbc:CityName>
|
||||||
|
<cbc:PostalZone>24105</cbc:PostalZone>
|
||||||
|
<cac:Country>
|
||||||
|
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
|
||||||
|
</cac:Country>
|
||||||
|
</cac:Address>
|
||||||
|
</cac:DeliveryLocation>
|
||||||
|
<cac:DeliveryParty>
|
||||||
|
<cac:PartyName>
|
||||||
|
<cbc:Name>Muster GmbH</cbc:Name>
|
||||||
|
</cac:PartyName>
|
||||||
|
</cac:DeliveryParty>
|
||||||
|
</cac:Delivery>
|
||||||
|
<cac:PaymentMeans>
|
||||||
|
<cbc:PaymentMeansCode>30</cbc:PaymentMeansCode>
|
||||||
|
<cac:PayeeFinancialAccount>
|
||||||
|
<cbc:ID>DE34700700100156919301</cbc:ID>
|
||||||
|
<cbc:Name>Alphabet Fuhrparkmanagement GmbH</cbc:Name>
|
||||||
|
<cac:FinancialInstitutionBranch>
|
||||||
|
<cbc:ID>DEUTDEMMXXX</cbc:ID>
|
||||||
|
</cac:FinancialInstitutionBranch>
|
||||||
|
</cac:PayeeFinancialAccount>
|
||||||
|
</cac:PaymentMeans>
|
||||||
|
<cac:PaymentTerms>
|
||||||
|
<cbc:Note>Rechnungsbetrag zahlbar ohne Abzug sofort nach Erhalt der Rechnung.</cbc:Note>
|
||||||
|
</cac:PaymentTerms>
|
||||||
|
<cac:TaxTotal>
|
||||||
|
<cbc:TaxAmount currencyID="EUR">161.69</cbc:TaxAmount>
|
||||||
|
<cac:TaxSubtotal>
|
||||||
|
<cbc:TaxableAmount currencyID="EUR">851.00</cbc:TaxableAmount>
|
||||||
|
<cbc:TaxAmount currencyID="EUR">161.69</cbc:TaxAmount>
|
||||||
|
<cac:TaxCategory>
|
||||||
|
<cbc:ID>S</cbc:ID>
|
||||||
|
<cbc:Percent>19.00</cbc:Percent>
|
||||||
|
<cac:TaxScheme>
|
||||||
|
<cbc:ID>VAT</cbc:ID>
|
||||||
|
</cac:TaxScheme>
|
||||||
|
</cac:TaxCategory>
|
||||||
|
</cac:TaxSubtotal>
|
||||||
|
</cac:TaxTotal>
|
||||||
|
<cac:LegalMonetaryTotal>
|
||||||
|
<cbc:LineExtensionAmount currencyID="EUR">851.00</cbc:LineExtensionAmount>
|
||||||
|
<cbc:TaxExclusiveAmount currencyID="EUR">851.00</cbc:TaxExclusiveAmount>
|
||||||
|
<cbc:TaxInclusiveAmount currencyID="EUR">1012.69</cbc:TaxInclusiveAmount>
|
||||||
|
<cbc:PayableAmount currencyID="EUR">1012.69</cbc:PayableAmount>
|
||||||
|
</cac:LegalMonetaryTotal>
|
||||||
|
<cac:InvoiceLine>
|
||||||
|
<cbc:ID>1</cbc:ID>
|
||||||
|
<cbc:Note>#AAI# Finanzrate vom 01.11.2024 bis 30.11.2024 #ABZ/Kennzeichen#SH-9 18E #AKG/Fahrgestellnummer#WBY51EJ080CR55555 #BA/Kilometerstand#0 #AKV/LeasingNr#63435555</cbc:Note>
|
||||||
|
<cbc:InvoicedQuantity unitCode="C62">1.00</cbc:InvoicedQuantity>
|
||||||
|
<cbc:LineExtensionAmount currencyID="EUR">851.00</cbc:LineExtensionAmount>
|
||||||
|
<cac:InvoicePeriod>
|
||||||
|
<cbc:StartDate>2024-11-01</cbc:StartDate>
|
||||||
|
<cbc:EndDate>2024-11-30</cbc:EndDate>
|
||||||
|
</cac:InvoicePeriod>
|
||||||
|
<cac:Item>
|
||||||
|
<cbc:Description>FL-Rate</cbc:Description>
|
||||||
|
<cbc:Name>FL-Rate</cbc:Name>
|
||||||
|
<cac:SellersItemIdentification>
|
||||||
|
<cbc:ID>90101</cbc:ID>
|
||||||
|
</cac:SellersItemIdentification>
|
||||||
|
<cac:ClassifiedTaxCategory>
|
||||||
|
<cbc:ID>S</cbc:ID>
|
||||||
|
<cbc:Percent>19.00</cbc:Percent>
|
||||||
|
<cac:TaxScheme>
|
||||||
|
<cbc:ID>VAT</cbc:ID>
|
||||||
|
</cac:TaxScheme>
|
||||||
|
</cac:ClassifiedTaxCategory>
|
||||||
|
</cac:Item>
|
||||||
|
<cac:Price>
|
||||||
|
<cbc:PriceAmount currencyID="EUR">851.00</cbc:PriceAmount>
|
||||||
|
<cbc:BaseQuantity>1.00</cbc:BaseQuantity>
|
||||||
|
</cac:Price>
|
||||||
|
</cac:InvoiceLine>
|
||||||
|
</ubl:Invoice>
|
||||||
Binary file not shown.
@@ -44,6 +44,12 @@
|
|||||||
<groupId>org.dom4j</groupId>
|
<groupId>org.dom4j</groupId>
|
||||||
<artifactId>dom4j</artifactId>
|
<artifactId>dom4j</artifactId>
|
||||||
<version>2.1.4</version>
|
<version>2.1.4</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>*</groupId>
|
||||||
|
<artifactId>*</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-io</groupId>
|
<groupId>commons-io</groupId>
|
||||||
|
|||||||
@@ -424,11 +424,6 @@ public class XMLValidator extends Validator {
|
|||||||
*/
|
*/
|
||||||
public void validateSchematron(String xml, String xsltFilename, int section, ESeverity defaultSeverity) throws IrrecoverableValidationError {
|
public void validateSchematron(String xml, String xsltFilename, int section, ESeverity defaultSeverity) throws IrrecoverableValidationError {
|
||||||
ISchematronResource aResSCH = null;
|
ISchematronResource aResSCH = null;
|
||||||
ESeverity severity=defaultSeverity;
|
|
||||||
if (defaultSeverity!=ESeverity.notice) {
|
|
||||||
severity=ESeverity.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
aResSCH = SchematronResourceXSLT.fromClassPath(xsltFilename);
|
aResSCH = SchematronResourceXSLT.fromClassPath(xsltFilename);
|
||||||
|
|
||||||
if (aResSCH != null) {
|
if (aResSCH != null) {
|
||||||
@@ -472,14 +467,15 @@ public class XMLValidator extends Validator {
|
|||||||
thisFailLocation = currentFailNode.getAttributes().getNamedItem("location").getNodeValue();
|
thisFailLocation = currentFailNode.getAttributes().getNamedItem("location").getNodeValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentFailNode.getAttributes().getNamedItem("flag") != null) {
|
ESeverity severity;
|
||||||
|
if (defaultSeverity == ESeverity.notice) {
|
||||||
|
severity = defaultSeverity;
|
||||||
|
} else if (currentFailNode.getAttributes().getNamedItem("flag") != null
|
||||||
|
&& currentFailNode.getAttributes().getNamedItem("flag").getNodeValue().equals("warning")) {
|
||||||
// the XR issues warnings with flag=warning
|
// the XR issues warnings with flag=warning
|
||||||
if (currentFailNode.getAttributes().getNamedItem("flag").getNodeValue().equals("warning")) {
|
severity = ESeverity.warning;
|
||||||
if (defaultSeverity!=ESeverity.notice) {
|
} else {
|
||||||
severity=ESeverity.warning;
|
severity = ESeverity.error;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeList failChilds = currentFailNode.getChildNodes();
|
NodeList failChilds = currentFailNode.getChildNodes();
|
||||||
|
|||||||
@@ -216,10 +216,10 @@ public class ZUGFeRDValidatorTest extends ResourceCase {
|
|||||||
|
|
||||||
assertThat(res).valueByXPath("count(//error)")
|
assertThat(res).valueByXPath("count(//error)")
|
||||||
.asInt()
|
.asInt()
|
||||||
.isEqualTo(1);
|
.isEqualTo(2);
|
||||||
assertThat(res).valueByXPath("count(//warning)")
|
assertThat(res).valueByXPath("count(//warning)")
|
||||||
.asInt()
|
.asInt()
|
||||||
.isEqualTo(3);
|
.isEqualTo(2);
|
||||||
|
|
||||||
assertThat(res).valueByXPath("count(//notice)")
|
assertThat(res).valueByXPath("count(//notice)")
|
||||||
.asInt()
|
.asInt()
|
||||||
|
|||||||
Reference in New Issue
Block a user