diff --git a/library/src/main/java/org/mustangproject/Item.java b/library/src/main/java/org/mustangproject/Item.java index 5c9d8976..eb3cc6cc 100644 --- a/library/src/main/java/org/mustangproject/Item.java +++ b/library/src/main/java/org/mustangproject/Item.java @@ -46,6 +46,8 @@ public class Item implements IZUGFeRDExportableItem { protected String parentLineID = null; protected String lineStatusReasonCode = null; protected TradeParty lineSeller; + protected String deliveryNoteReferencedDocumentID = null; + protected Date deliveryNoteReferencedDocumentDate = null; //protected HashMap attributes = new HashMap<>(); /*** @@ -187,6 +189,19 @@ public class Item implements IZUGFeRDExportableItem { } }); + itemMap.getAsNodeMap("SpecifiedLineTradeDelivery").ifPresent(icnm -> { + icnm.getAsNodeMap("DeliveryNoteReferencedDocument").ifPresent(dn -> { + dn.getAsString("IssuerAssignedID") + .ifPresent(this::setDeliveryNoteReferencedDocumentID); + + dn.getAsNodeMap("FormattedIssueDateTime") + .flatMap(fdt -> fdt.getNode("DateTimeString")) + .map(XMLTools::getNodeValue) + .map(XMLTools::tryDate) + .ifPresent(this::setDeliveryNoteReferencedDocumentDate); + }); + }); + itemMap.getAsNodeMap("SpecifiedLineTradeSettlement", "SpecifiedSupplyChainTradeSettlement").ifPresent(icnm -> { icnm.getAsNodeMap("ApplicableTradeTax") .flatMap(cnm -> cnm.getAsBigDecimal("RateApplicablePercent", "ApplicablePercent")) @@ -697,4 +712,26 @@ public class Item implements IZUGFeRDExportableItem { return this.lineSeller; } + @Override + public String getDeliveryNoteReferencedDocumentID() { + return deliveryNoteReferencedDocumentID; + } + + + public Item setDeliveryNoteReferencedDocumentID(String deliveryNoteReferencedDocumentID) { + this.deliveryNoteReferencedDocumentID = deliveryNoteReferencedDocumentID; + return this; + } + + @Override + public Date getDeliveryNoteReferencedDocumentDate() { + return deliveryNoteReferencedDocumentDate; + } + + + public Item setDeliveryNoteReferencedDocumentDate(Date deliveryNoteReferencedDocumentDate) { + this.deliveryNoteReferencedDocumentDate = deliveryNoteReferencedDocumentDate; + return this; + } + } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java index 5d16ab33..3d8ed971 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableItem.java @@ -247,4 +247,24 @@ public interface IZUGFeRDExportableItem extends IAbsoluteValueProvider{ return null; } + /** + * get delivery note document ID (per Item - ZUGFeRD EXTENDED) + * rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedLineTradeDelivery/ram:DeliveryNoteReferencedDocument/IssuerAssignedID + * + * @return the ID of the delivery note document + */ + default String getDeliveryNoteReferencedDocumentID() { + return null; + } + + /** + * get delivery note document date (per Item - ZUGFeRD EXTENDED) + * rsm:SupplyChainTradeTransaction/ram:IncludedSupplyChainTradeLineItem/ram:SpecifiedLineTradeDelivery/ram:DeliveryNoteReferencedDocument/FormattedIssueDateTime + * + * @return the date of the delivery note document + */ + default Date getDeliveryNoteReferencedDocumentDate() { + return null; + } + } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 7d8cd0fd..372b2547 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -534,8 +534,20 @@ public class ZUGFeRD2PullProvider implements IXMLProvider { xml += "" + "" + "" - + quantityFormat(currentItem.getQuantity()) + "" - + "" + + quantityFormat(currentItem.getQuantity()) + ""; + + if (currentItem.getDeliveryNoteReferencedDocumentID() != null && !currentItem.getDeliveryNoteReferencedDocumentID().trim().isEmpty()) { + xml += ""; + xml += "" + XMLTools.encodeXML(currentItem.getDeliveryNoteReferencedDocumentID()) + ""; + if (currentItem.getDeliveryNoteReferencedDocumentDate() != null) { + final SimpleDateFormat dateFormat102 = new SimpleDateFormat("yyyyMMdd"); + xml += ""+XMLTools.encodeXML(dateFormat102.format(currentItem.getDeliveryNoteReferencedDocumentDate()))+""; + } + xml += ""; + + } + + xml += "" + "" + "" + "VAT"; diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java index 3f2cd02d..72860003 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java @@ -680,6 +680,7 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter { for (int i = 0; i < nl.getLength(); i++) { final Node nn = nl.item(i); Node node = null; + Node subnode = null; if (nn.getLocalName() != null) { switch (nn.getLocalName()) { case "SpecifiedLineTradeAgreement": @@ -738,6 +739,24 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter { case "SpecifiedSupplyChainTradeDelivery": node = getNodeByName(nn.getChildNodes(), "BilledQuantity"); lineItem.setQuantity(XMLTools.tryBigDecimal(node)); + + node = getNodeByName(nn.getChildNodes(), "DeliveryNoteReferencedDocument"); + if (node != null) { + subnode = getNodeByName(node.getChildNodes(), "IssuerAssignedID"); + if (subnode != null) { + lineItem.setDeliveryNoteReferencedDocumentID(XMLTools.getNodeValue(subnode)); + } + node = getNodeByName(node.getChildNodes(), "FormattedIssueDateTime"); + if (node != null) { + NodeList FormattedIssueDateTimeChilds = node.getChildNodes(); + for (int dateChildIndex = 0; dateChildIndex < FormattedIssueDateTimeChilds.getLength(); dateChildIndex++) { + if ((FormattedIssueDateTimeChilds.item(dateChildIndex).getLocalName() != null) + && (FormattedIssueDateTimeChilds.item(dateChildIndex).getLocalName().equals("DateTimeString"))) { + lineItem.setDeliveryNoteReferencedDocumentDate(XMLTools.tryDate(FormattedIssueDateTimeChilds.item(dateChildIndex))); + } + } + } + } break; case "SpecifiedLineTradeSettlement": diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java index 4c572aa7..427b434e 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java @@ -28,6 +28,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.text.SimpleDateFormat; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class MustangReaderWriterCustomXMLTest extends TestCase { @@ -100,6 +102,12 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { "\n" + "\n" + "1.0000\n" + + "\n" + + "deliverynote123\n" + + "\n" + + "20260114\n" + + "\n" + + "\n" + "\n" + "\n" + "\n" + @@ -279,6 +287,12 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00"); assertEquals(zi.getHolder(), "Bei Spiel GmbH"); assertEquals(zi.getForeignReference(), "RE-20171118/506"); + assertEquals(zi.getLineItemList().get(0).getDeliveryNoteReferencedDocumentID(), "deliverynote123"); + try { + assertEquals(zi.getLineItemList().get(0).getDeliveryNoteReferencedDocumentDate(), new SimpleDateFormat("dd.MM.yyyy").parse("14.01.2026")); + } catch (ParseException e) { + e.printStackTrace(); + } } /** diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java index 1f81e373..117c5bfa 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2PushTest.java @@ -611,7 +611,11 @@ public class ZF2PushTest extends TestCase { .setInvoicer( new TradeParty("Abweichender Rechnungssteller", "Teststr.12", "04711", "Entenhausen", "DE") ) .setInvoicee( new TradeParty("Abweichender Rechnungsempfänger", "Teststr.42", "00815", "Entenhausen", "DE") ) .addItem(new Item(new Product("Testprodukt", "", "H87", new BigDecimal(16)).addGlobalID(gtin).setSellerAssignedID("4711"), price, new BigDecimal(1.0)).setId("a123"). - addAdditionalReference(dr2).addBuyerOrderReferencedDocumentID("orderId").addBuyerOrderReferencedDocumentLineID("xxx").addReferencedLineID("xxx").addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15"))) + addAdditionalReference(dr2).addBuyerOrderReferencedDocumentID("orderId").addBuyerOrderReferencedDocumentLineID("xxx").addReferencedLineID("xxx") + .addNote("item level 1/1").addAllowance(new Allowance(new BigDecimal(0.02)).setReason("item discount").setTaxPercent(new BigDecimal(16))).setDetailedDeliveryPeriod(sdf.parse("2020-01-13"), sdf.parse("2020-01-15")) + .setDeliveryNoteReferencedDocumentID("deliverynote123") + .setDeliveryNoteReferencedDocumentDate(new SimpleDateFormat("dd.MM.yyyy").parse("14.01.2026")) + ) .addCharge(new Charge(new BigDecimal(0.5)).setReason("quick delivery charge").setTaxPercent(new BigDecimal(16))) .addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16))) .addCashDiscount(new CashDiscount(new BigDecimal(2), 14)) @@ -647,6 +651,12 @@ public class ZF2PushTest extends TestCase { assertTrue(zi.getUTF8().contains(occurrenceTo)); assertTrue(zi.getUTF8().contains(contractID)); assertEquals(zi.importedInvoice.getZFItems()[0].getId(), "a123"); + assertEquals(zi.importedInvoice.getZFItems()[0].getDeliveryNoteReferencedDocumentID(), "deliverynote123"); + try { + assertEquals(zi.importedInvoice.getZFItems()[0].getDeliveryNoteReferencedDocumentDate(), new SimpleDateFormat("dd.MM.yyyy").parse("14.01.2026")); + } catch (ParseException e) { + e.printStackTrace(); + } assertTrue(zi.getUTF8().contains("20200113")); // to contain item delivery periods assertTrue(zi.getUTF8().contains("20200115")); // to contain item delivery periods