Add list of invoice referenced documents (BG-3) to invoice

This commit is contained in:
cs
2024-12-20 14:29:34 +01:00
parent 3d0d09937a
commit 5d7415860a
8 changed files with 135 additions and 11 deletions

View File

@@ -38,7 +38,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Invoice implements IExportableTransaction { public class Invoice implements IExportableTransaction {
protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, invoiceReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null; protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null;
protected Date issueDate = null, dueDate = null, deliveryDate = null; protected Date issueDate = null, dueDate = null, deliveryDate = null;
protected TradeParty sender = null, recipient = null, deliveryAddress = null, payee = null; protected TradeParty sender = null, recipient = null, deliveryAddress = null, payee = null;
protected ArrayList<CashDiscount> cashDiscounts = null; protected ArrayList<CashDiscount> cashDiscounts = null;
@@ -57,7 +57,12 @@ public class Invoice implements IExportableTransaction {
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>(), protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>(),
Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>(); Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>();
protected IZUGFeRDPaymentTerms paymentTerms = null; protected IZUGFeRDPaymentTerms paymentTerms = null;
protected String invoiceReferencedDocumentID = null;
protected Date invoiceReferencedIssueDate; protected Date invoiceReferencedIssueDate;
// New field for storing Invoiced Object Identifier (BG-3)
protected ArrayList<ReferencedDocument> invoiceReferencedDocuments = null;
protected String specifiedProcuringProjectID = null; protected String specifiedProcuringProjectID = null;
protected String specifiedProcuringProjectName = null; protected String specifiedProcuringProjectName = null;
protected String despatchAdviceReferencedDocumentID = null; protected String despatchAdviceReferencedDocumentID = null;
@@ -148,6 +153,7 @@ public class Invoice implements IExportableTransaction {
*/ */
public Invoice setCorrection(String number) { public Invoice setCorrection(String number) {
setInvoiceReferencedDocumentID(number); setInvoiceReferencedDocumentID(number);
addInvoiceReferencedDocument(new ReferencedDocument(number));
documentCode = DocumentCodeTypeConstants.CORRECTEDINVOICE; documentCode = DocumentCodeTypeConstants.CORRECTEDINVOICE;
return this; return this;
} }
@@ -546,6 +552,26 @@ public class Invoice implements IExportableTransaction {
return this; return this;
} }
// Getter for BG-3
@Override
public ArrayList<ReferencedDocument> getInvoiceReferencedDocuments() {
return invoiceReferencedDocuments;
}
// Setter for BG-3
public void setInvoiceReferencedDocuments(ArrayList<ReferencedDocument> invoiceReferencedDocuments) {
this.invoiceReferencedDocuments = invoiceReferencedDocuments;
}
// Method to add a single ReferencedDocument for BG-3
public Invoice addInvoiceReferencedDocument(ReferencedDocument doc) {
if (invoiceReferencedDocuments == null) {
invoiceReferencedDocuments = new ArrayList<>();
}
invoiceReferencedDocuments.add(doc);
return this;
}
@Override @Override
public IZUGFeRDAllowanceCharge[] getZFAllowances() { public IZUGFeRDAllowanceCharge[] getZFAllowances() {
if (Allowances.isEmpty()) { if (Allowances.isEmpty()) {

View File

@@ -2,6 +2,8 @@ package org.mustangproject;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.Date;
import org.mustangproject.ZUGFeRD.IReferencedDocument; import org.mustangproject.ZUGFeRD.IReferencedDocument;
import org.mustangproject.util.NodeMap; import org.mustangproject.util.NodeMap;
import org.w3c.dom.Node; import org.w3c.dom.Node;
@@ -13,20 +15,33 @@ public class ReferencedDocument implements IReferencedDocument {
String issuerAssignedID; String issuerAssignedID;
String typeCode; String typeCode;
String referenceTypeCode; String referenceTypeCode;
Date formattedIssueDateTime;
public ReferencedDocument(String issuerAssignedID, String typeCode, String referenceTypeCode) { public ReferencedDocument(String issuerAssignedID, String typeCode, String referenceTypeCode) {
this.issuerAssignedID = issuerAssignedID; this(issuerAssignedID);
this.typeCode = typeCode; this.typeCode = typeCode;
this.referenceTypeCode = referenceTypeCode; this.referenceTypeCode = referenceTypeCode;
} }
public ReferencedDocument(String issuerAssignedID, String referenceTypeCode) { public ReferencedDocument(String issuerAssignedID, String typeCode, String referenceTypeCode, Date formattedIssueDateTime) {
this.issuerAssignedID = issuerAssignedID; this(issuerAssignedID, typeCode, referenceTypeCode);
this.typeCode = "916"; // additional invoice related document this.formattedIssueDateTime = formattedIssueDateTime;
this.referenceTypeCode = referenceTypeCode;
} }
/*** public ReferencedDocument(String issuerAssignedID, String referenceTypeCode) {
this(issuerAssignedID, "916", referenceTypeCode); // additional invoice related document
}
public ReferencedDocument(String issuerAssingedID, Date formattedIssueDateTime) {
this(issuerAssingedID);
this.formattedIssueDateTime = formattedIssueDateTime;
}
public ReferencedDocument(String issuerAssignedID) {
this.issuerAssignedID = issuerAssignedID;
}
/***
* sets an ID assigned by the sender * sets an ID assigned by the sender
* @param issuerAssignedID the ID as a string :-) * @param issuerAssignedID the ID as a string :-)
*/ */
@@ -50,6 +65,15 @@ public class ReferencedDocument implements IReferencedDocument {
this.referenceTypeCode = referenceTypeCode; this.referenceTypeCode = referenceTypeCode;
} }
/**
* issue date of this line
*
* @param formattedIssueDateTime as Date
*/
public void setFormattedIssueDateTime(Date formattedIssueDateTime) {
this.formattedIssueDateTime = formattedIssueDateTime;
}
@Override @Override
public String getIssuerAssignedID() { public String getIssuerAssignedID() {
return issuerAssignedID; return issuerAssignedID;
@@ -65,6 +89,12 @@ public class ReferencedDocument implements IReferencedDocument {
return referenceTypeCode; return referenceTypeCode;
} }
@Override
public Date getFormattedIssueDateTime()
{
return formattedIssueDateTime;
}
public static ReferencedDocument fromNode(Node node) { public static ReferencedDocument fromNode(Node node) {
if (!node.hasChildNodes()) { if (!node.hasChildNodes()) {
return null; return null;
@@ -72,6 +102,7 @@ public class ReferencedDocument implements IReferencedDocument {
NodeMap nodes = new NodeMap(node); NodeMap nodes = new NodeMap(node);
return new ReferencedDocument(nodes.getAsStringOrNull("IssuerAssignedID", "ID"), return new ReferencedDocument(nodes.getAsStringOrNull("IssuerAssignedID", "ID"),
nodes.getAsStringOrNull("TypeCode", "DocumentTypeCode"), nodes.getAsStringOrNull("TypeCode", "DocumentTypeCode"),
nodes.getAsStringOrNull("ReferenceTypeCode")); nodes.getAsStringOrNull("ReferenceTypeCode"),
XMLTools.tryDate(nodes.getAsStringOrNull("FormattedIssueDateTime")));
} }
} }

View File

@@ -30,11 +30,13 @@ package org.mustangproject.ZUGFeRD;
* */ * */
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.mustangproject.FileAttachment; import org.mustangproject.FileAttachment;
import org.mustangproject.IncludedNote; import org.mustangproject.IncludedNote;
import org.mustangproject.ReferencedDocument;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants; import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
/*** /***
@@ -424,14 +426,24 @@ public interface IExportableTransaction {
* *
* @return the ID of the document * @return the ID of the document
*/ */
@Deprecated
default String getInvoiceReferencedDocumentID() { default String getInvoiceReferencedDocumentID() {
return null; return null;
} }
@Deprecated
default Date getInvoiceReferencedIssueDate() { default Date getInvoiceReferencedIssueDate() {
return null; return null;
} }
/**
* Getter for BG-3
* @return list of documents
*/
default ArrayList<ReferencedDocument> getInvoiceReferencedDocuments() {
return null;
}
/** /**
* get the issue timestamp of the BuyerOrderReferencedDocument, which sits in * get the issue timestamp of the BuyerOrderReferencedDocument, which sits in
* the ApplicableSupplyChainTradeAgreement * the ApplicableSupplyChainTradeAgreement

View File

@@ -1,5 +1,7 @@
package org.mustangproject.ZUGFeRD; package org.mustangproject.ZUGFeRD;
import java.util.Date;
public interface IReferencedDocument { public interface IReferencedDocument {
/*** /***
@@ -20,4 +22,12 @@ public interface IReferencedDocument {
*/ */
String getReferenceTypeCode(); String getReferenceTypeCode();
/***
*
* issue date of this line
*
* @return date of the issue
*/
Date getFormattedIssueDateTime();
} }

View File

@@ -459,6 +459,19 @@ public class OXPullProvider extends ZUGFeRD2PullProvider {
} }
xml += "</ram:InvoiceReferencedDocument>"; xml += "</ram:InvoiceReferencedDocument>";
} }
if (trans.getInvoiceReferencedDocuments() != null) {
for (var doc : trans.getInvoiceReferencedDocuments()) {
xml += "<ram:InvoiceReferencedDocument>"
+ "<ram:IssuerAssignedID>"
+ XMLTools.encodeXML(doc.getIssuerAssignedID()) + "</ram:IssuerAssignedID>";
if (doc.getFormattedIssueDateTime() != null) {
xml += "<ram:FormattedIssueDateTime>"
+ DATE.qdtFormat(doc.getFormattedIssueDateTime())
+ "</ram:FormattedIssueDateTime>";
}
xml += "</ram:InvoiceReferencedDocument>";
}
}
xml += "</ram:ApplicableHeaderTradeSettlement>"; xml += "</ram:ApplicableHeaderTradeSettlement>";
// + " <IncludedSupplyChainTradeLineItem>" // + " <IncludedSupplyChainTradeLineItem>"

View File

@@ -893,6 +893,19 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
} }
xml += "</ram:InvoiceReferencedDocument>"; xml += "</ram:InvoiceReferencedDocument>";
} }
if (trans.getInvoiceReferencedDocuments() != null) {
for (var doc : trans.getInvoiceReferencedDocuments()) {
xml += "<ram:InvoiceReferencedDocument>"
+ "<ram:IssuerAssignedID>"
+ XMLTools.encodeXML(doc.getIssuerAssignedID()) + "</ram:IssuerAssignedID>";
if (doc.getFormattedIssueDateTime() != null) {
xml += "<ram:FormattedIssueDateTime>"
+ DATE.qdtFormat(doc.getFormattedIssueDateTime())
+ "</ram:FormattedIssueDateTime>";
}
xml += "</ram:InvoiceReferencedDocument>";
}
}
xml += "</ram:ApplicableHeaderTradeSettlement>"; xml += "</ram:ApplicableHeaderTradeSettlement>";
// + "<IncludedSupplyChainTradeLineItem>\n" // + "<IncludedSupplyChainTradeLineItem>\n"

View File

@@ -816,6 +816,23 @@ public class ZUGFeRDInvoiceImporter {
} }
zpp.setInvoiceReferencedDocumentID(extractString("//*[local-name()=\"InvoiceReferencedDocument\"]/*[local-name()=\"IssuerAssignedID\"]|//*[local-name()=\"BillingReference\"]/*[local-name()=\"InvoiceDocumentReference\"]/*[local-name()=\"ID\"]")); zpp.setInvoiceReferencedDocumentID(extractString("//*[local-name()=\"InvoiceReferencedDocument\"]/*[local-name()=\"IssuerAssignedID\"]|//*[local-name()=\"BillingReference\"]/*[local-name()=\"InvoiceDocumentReference\"]/*[local-name()=\"ID\"]"));
xpr = xpath.compile("//*[local-name()=\"InvoiceReferencedDocument\"]");
NodeList nodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (nodes.getLength() != 0) {
for (int i = 0; i < nodes.getLength(); i++) {
Node currentItemNode = nodes.item(i);
ReferencedDocument doc = ReferencedDocument.fromNode(currentItemNode);
if (doc != null
&& (!Objects.equals(zpp.getInvoiceReferencedDocumentID(), doc.getIssuerAssignedID())
|| !Objects.equals(zpp.getInvoiceReferencedIssueDate(), doc.getFormattedIssueDateTime())))
{
zpp.addInvoiceReferencedDocument(doc);
}
}
}
zpp.setOwnOrganisationName(extractString("//*[local-name()=\"SellerTradeParty\"]/*[local-name()=\"Name\"]|//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyName\"]").trim()); zpp.setOwnOrganisationName(extractString("//*[local-name()=\"SellerTradeParty\"]/*[local-name()=\"Name\"]|//*[local-name()=\"AccountingSupplierParty\"]/*[local-name()=\"Party\"]/*[local-name()=\"PartyName\"]").trim());
String rounding = extractString("//*[local-name()=\"SpecifiedTradeSettlementHeaderMonetarySummation\"]/*[local-name()=\"RoundingAmount\"]|//*[local-name()=\"LegalMonetaryTotal\"]/*[local-name()=\"Party\"]/*[local-name()=\"PayableRoundingAmount\"]"); String rounding = extractString("//*[local-name()=\"SpecifiedTradeSettlementHeaderMonetarySummation\"]/*[local-name()=\"RoundingAmount\"]|//*[local-name()=\"LegalMonetaryTotal\"]/*[local-name()=\"Party\"]/*[local-name()=\"PayableRoundingAmount\"]");
@@ -834,7 +851,7 @@ public class ZUGFeRDInvoiceImporter {
} }
xpr = xpath.compile("//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]|//*[local-name()=\"InvoiceLine\"]"); xpr = xpath.compile("//*[local-name()=\"IncludedSupplyChainTradeLineItem\"]|//*[local-name()=\"InvoiceLine\"]");
NodeList nodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); nodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (nodes.getLength() != 0) { if (nodes.getLength() != 0) {
for (int i = 0; i < nodes.getLength(); i++) { for (int i = 0; i < nodes.getLength(); i++) {

View File

@@ -542,7 +542,7 @@ public class ZF2PushTest extends TestCase {
.addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16))) .addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16)))
.addCashDiscount(new CashDiscount(new BigDecimal(2), 14)) .addCashDiscount(new CashDiscount(new BigDecimal(2), 14))
.setDeliveryDate(sdf.parse("2020-11-02")).setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE) .setDeliveryDate(sdf.parse("2020-11-02")).setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE)
.setInvoiceReferencedDocumentID("abc123") .setInvoiceReferencedDocumentID("abc123").addInvoiceReferencedDocument(new ReferencedDocument("abcd1234"))
); );
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); e.printStackTrace();
@@ -587,6 +587,8 @@ public class ZF2PushTest extends TestCase {
Invoice i = zii.extractInvoice(); Invoice i = zii.extractInvoice();
assertEquals("abc123", i.getInvoiceReferencedDocumentID()); assertEquals("abc123", i.getInvoiceReferencedDocumentID());
assertEquals(1, i.getInvoiceReferencedDocuments().size());
assertEquals("abcd1234", i.getInvoiceReferencedDocuments().get(0).getIssuerAssignedID());
assertEquals("4304171000002", i.getRecipient().getGlobalID()); assertEquals("4304171000002", i.getRecipient().getGlobalID());
assertEquals("2001015001325", i.getZFItems()[0].getProduct().getGlobalID()); assertEquals("2001015001325", i.getZFItems()[0].getProduct().getGlobalID());
assertEquals(orgID, i.getSender().getID()); assertEquals(orgID, i.getSender().getID());