diff --git a/library/src/main/java/org/mustangproject/IncludedNote.java b/library/src/main/java/org/mustangproject/IncludedNote.java
index eff8385b..e721ffd1 100644
--- a/library/src/main/java/org/mustangproject/IncludedNote.java
+++ b/library/src/main/java/org/mustangproject/IncludedNote.java
@@ -14,7 +14,7 @@ public class IncludedNote {
private static final String SUBJECT_CODE_START = "";
private static final String SUBJECT_CODE_END = "";
- private IncludedNote(String content, SubjectCode subjectCode) {
+ public IncludedNote(String content, SubjectCode subjectCode) {
this.content = content;
this.subjectCode = subjectCode;
}
diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java
index d726ed08..4e644bd6 100644
--- a/library/src/main/java/org/mustangproject/Item.java
+++ b/library/src/main/java/org/mustangproject/Item.java
@@ -12,7 +12,9 @@ import org.w3c.dom.NodeList;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Date;
+import java.util.List;
/***
* describes any invoice line
@@ -37,6 +39,7 @@ public class Item implements IZUGFeRDExportableItem {
protected ArrayList additionalReference = null;
protected ArrayList Allowances = new ArrayList<>();
protected ArrayList Charges = new ArrayList<>();
+ protected List includedNotes = null;
/***
* default constructor
@@ -125,6 +128,38 @@ public class Item implements IZUGFeRDExportableItem {
icnm.getAllNodes("AdditionalReferencedDocument").map(ReferencedDocument::fromNode).forEach(this::addAdditionalReference);
});
+
+ itemMap.getAsString("Note").ifPresent(this::addNote);
+ itemMap.getAsNodeMap("AssociatedDocumentLineDocument").ifPresent(adld -> {
+ List 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) {
@@ -372,4 +407,19 @@ public class Item implements IZUGFeRDExportableItem {
return detailedDeliveryPeriodTo;
}
+ public IZUGFeRDExportableItem addNotes(Collection notes) {
+ if (notes == null) {
+ return this;
+ }
+ if (includedNotes == null) {
+ includedNotes = new ArrayList<>();
+ }
+ includedNotes.addAll(notes);
+ return this;
+ }
+
+ @Override
+ public List getNotesWithSubjectCode() {
+ return includedNotes;
+ }
}
diff --git a/library/src/main/java/org/mustangproject/SubjectCode.java b/library/src/main/java/org/mustangproject/SubjectCode.java
index c58070fd..808c09d4 100644
--- a/library/src/main/java/org/mustangproject/SubjectCode.java
+++ b/library/src/main/java/org/mustangproject/SubjectCode.java
@@ -36,5 +36,9 @@ public enum SubjectCode {
/**
* Discount and bonus agreements
*/
- AAK
+ AAK,
+ /**
+ * Vehicle licence number
+ */
+ ABZ
}
diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
index e5e25cae..c2f57f9e 100644
--- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
+++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java
@@ -28,7 +28,9 @@ package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
import java.util.Date;
+import java.util.List;
+import org.mustangproject.IncludedNote;
import org.mustangproject.Item;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -153,4 +155,7 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{
return null;
}
+ default List getNotesWithSubjectCode() {
+ return null;
+ }
}
diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java
index b9342e1e..e32bc28f 100644
--- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java
+++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java
@@ -22,12 +22,15 @@ package org.mustangproject.ZUGFeRD;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.apache.commons.codec.binary.StringUtils;
import org.junit.jupiter.api.Test;
import org.mustangproject.*;
import javax.xml.xpath.XPathExpressionException;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
@@ -397,4 +400,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);
+ }
}
diff --git a/library/src/test/resources/TESTXRECHNUNG_INVDSS_012015776085.XML b/library/src/test/resources/TESTXRECHNUNG_INVDSS_012015776085.XML
new file mode 100644
index 00000000..1541326d
--- /dev/null
+++ b/library/src/test/resources/TESTXRECHNUNG_INVDSS_012015776085.XML
@@ -0,0 +1,157 @@
+
+ urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ 2015776085
+ 2024-11-01
+ 380
+ #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.
+ #PAI# Rechnungsbetrag zahlbar ohne Abzug sofort nach Erhalt der Rechnung.
+ EUR
+ 02-ZZ987654-99
+
+ 2024-11-01
+ 2024-11-30
+
+
+ N/A
+
+
+ 63435555
+
+
+
+ DE238574172
+
+ Alphabet Fuhrparkmanagement GmbH
+
+
+ Lilienthalallee 26
+ München
+ 80786
+
+ DE
+
+
+
+ DE238574172
+
+ VAT
+
+
+
+ Alphabet Fuhrparkmanagement GmbH
+ HRB 181098
+
+
+ Yildiz Tolga
+ +49899--
+ Tolga.Yildiz@alphabet.de
+
+
+
+
+
+ N/A
+
+ 00987654
+
+
+ Muster GmbH
+
+
+ Musterweg 1
+ Kiel
+ 24105
+
+ DE
+
+
+
+ Muster GmbH
+
+
+ Mustermann Max
+
+
+
+
+ 2024-11-30
+
+ 00987654
+
+ Musterweg 1
+ Kiel
+ 24105
+
+ DE
+
+
+
+
+
+ Muster GmbH
+
+
+
+
+ 30
+
+ DE34700700100156919301
+ Alphabet Fuhrparkmanagement GmbH
+
+ DEUTDEMMXXX
+
+
+
+
+ Rechnungsbetrag zahlbar ohne Abzug sofort nach Erhalt der Rechnung.
+
+
+ 161.69
+
+ 851.00
+ 161.69
+
+ S
+ 19.00
+
+ VAT
+
+
+
+
+
+ 851.00
+ 851.00
+ 1012.69
+ 1012.69
+
+
+ 1
+ #AAI# Finanzrate vom 01.11.2024 bis 30.11.2024 #ABZ/Kennzeichen#SH-9 18E #AKG/Fahrgestellnummer#WBY51EJ080CR55555 #BA/Kilometerstand#0 #AKV/LeasingNr#63435555
+ 1.00
+ 851.00
+
+ 2024-11-01
+ 2024-11-30
+
+
+ FL-Rate
+ FL-Rate
+
+ 90101
+
+
+ S
+ 19.00
+
+ VAT
+
+
+
+
+ 851.00
+ 1.00
+
+
+
diff --git a/library/src/test/resources/ZTESTZUGFERD_1_INVDSS_012015738820PDF-1.pdf b/library/src/test/resources/ZTESTZUGFERD_1_INVDSS_012015738820PDF-1.pdf
new file mode 100644
index 00000000..7b220689
Binary files /dev/null and b/library/src/test/resources/ZTESTZUGFERD_1_INVDSS_012015738820PDF-1.pdf differ