Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

This adds support for multiple invoice referenced documents (BG-3) #631

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion library/src/main/java/org/mustangproject/Invoice.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
@JsonInclude(JsonInclude.Include.NON_EMPTY)
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 TradeParty sender = null, recipient = null, deliveryAddress = null, payee = null;
protected ArrayList<CashDiscount> cashDiscounts = null;
Expand All @@ -57,7 +57,12 @@ public class Invoice implements IExportableTransaction {
protected ArrayList<IZUGFeRDAllowanceCharge> Allowances = new ArrayList<>(),
Charges = new ArrayList<>(), LogisticsServiceCharges = new ArrayList<>();
protected IZUGFeRDPaymentTerms paymentTerms = null;

protected String invoiceReferencedDocumentID = null;
protected Date invoiceReferencedIssueDate;
// New field for storing Invoiced Object Identifier (BG-3)
protected ArrayList<ReferencedDocument> invoiceReferencedDocuments = null;

protected String specifiedProcuringProjectID = null;
protected String specifiedProcuringProjectName = null;
protected String despatchAdviceReferencedDocumentID = null;
Expand Down Expand Up @@ -148,6 +153,7 @@ public Invoice setNumber(String number) {
*/
public Invoice setCorrection(String number) {
setInvoiceReferencedDocumentID(number);
addInvoiceReferencedDocument(new ReferencedDocument(number));
documentCode = DocumentCodeTypeConstants.CORRECTEDINVOICE;
return this;
}
Expand Down Expand Up @@ -546,6 +552,26 @@ public Invoice setSender(TradeParty sender) {
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
public IZUGFeRDAllowanceCharge[] getZFAllowances() {
if (Allowances.isEmpty()) {
Expand Down
41 changes: 36 additions & 5 deletions library/src/main/java/org/mustangproject/ReferencedDocument.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.Date;

import org.mustangproject.ZUGFeRD.IReferencedDocument;
import org.mustangproject.util.NodeMap;
import org.w3c.dom.Node;
Expand All @@ -13,20 +15,33 @@ public class ReferencedDocument implements IReferencedDocument {
String issuerAssignedID;
String typeCode;
String referenceTypeCode;
Date formattedIssueDateTime;

public ReferencedDocument(String issuerAssignedID, String typeCode, String referenceTypeCode) {
this.issuerAssignedID = issuerAssignedID;
this(issuerAssignedID);
this.typeCode = typeCode;
this.referenceTypeCode = referenceTypeCode;
}

public ReferencedDocument(String issuerAssignedID, String typeCode, String referenceTypeCode, Date formattedIssueDateTime) {
this(issuerAssignedID, typeCode, referenceTypeCode);
this.formattedIssueDateTime = formattedIssueDateTime;
}

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;
this.typeCode = "916"; // additional invoice related document
this.referenceTypeCode = referenceTypeCode;
}

/***
/***
* sets an ID assigned by the sender
* @param issuerAssignedID the ID as a string :-)
*/
Expand All @@ -50,6 +65,15 @@ public void setReferenceTypeCode(String referenceTypeCode) {
this.referenceTypeCode = referenceTypeCode;
}

/**
* issue date of this line
*
* @param formattedIssueDateTime as Date
*/
public void setFormattedIssueDateTime(Date formattedIssueDateTime) {
this.formattedIssueDateTime = formattedIssueDateTime;
}

@Override
public String getIssuerAssignedID() {
return issuerAssignedID;
Expand All @@ -65,13 +89,20 @@ public String getReferenceTypeCode() {
return referenceTypeCode;
}

@Override
public Date getFormattedIssueDateTime()
{
return formattedIssueDateTime;
}

public static ReferencedDocument fromNode(Node node) {
if (!node.hasChildNodes()) {
return null;
}
NodeMap nodes = new NodeMap(node);
return new ReferencedDocument(nodes.getAsStringOrNull("IssuerAssignedID", "ID"),
nodes.getAsStringOrNull("TypeCode", "DocumentTypeCode"),
nodes.getAsStringOrNull("ReferenceTypeCode"));
nodes.getAsStringOrNull("ReferenceTypeCode"),
XMLTools.tryDate(nodes.getAsStringOrNull("FormattedIssueDateTime")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@
* */

import java.math.BigDecimal;
import java.util.Date;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.mustangproject.FileAttachment;
import org.mustangproject.IncludedNote;
import org.mustangproject.ReferencedDocument;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;

/***
Expand Down Expand Up @@ -424,13 +426,23 @@ default String getBuyerOrderReferencedDocumentID() {
*
* @return the ID of the document
*/
@Deprecated
default String getInvoiceReferencedDocumentID() {
return null;
}

@Deprecated
default Date getInvoiceReferencedIssueDate() {
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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.mustangproject.ZUGFeRD;

import java.util.Date;

public interface IReferencedDocument {

/***
Expand All @@ -20,4 +22,12 @@ public interface IReferencedDocument {
*/
String getReferenceTypeCode();

/***
*
* issue date of this line
*
* @return date of the issue
*/
Date getFormattedIssueDateTime();

}
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,19 @@ public void generateXML(IExportableTransaction trans) {
}
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>";
// + " <IncludedSupplyChainTradeLineItem>"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,19 @@ public void generateXML(IExportableTransaction trans) {
}
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>";
// + "<IncludedSupplyChainTradeLineItem>\n"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,23 @@ public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseEx
}
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());

String rounding = extractString("//*[local-name()=\"SpecifiedTradeSettlementHeaderMonetarySummation\"]/*[local-name()=\"RoundingAmount\"]|//*[local-name()=\"LegalMonetaryTotal\"]/*[local-name()=\"Party\"]/*[local-name()=\"PayableRoundingAmount\"]");
Expand All @@ -834,7 +851,7 @@ public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseEx
}

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) {
for (int i = 0; i < nodes.getLength(); i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ public void testPushEdge() {
.addAllowance(new Allowance(new BigDecimal(0.2)).setReason("discount").setTaxPercent(new BigDecimal(16)))
.addCashDiscount(new CashDiscount(new BigDecimal(2), 14))
.setDeliveryDate(sdf.parse("2020-11-02")).setNumber(number).setVATDueDateTypeCode(EventTimeCodeTypeConstants.PAYMENT_DATE)
.setInvoiceReferencedDocumentID("abc123")
.setInvoiceReferencedDocumentID("abc123").addInvoiceReferencedDocument(new ReferencedDocument("abcd1234"))
);
} catch (ParseException e) {
e.printStackTrace();
Expand Down Expand Up @@ -587,6 +587,8 @@ public void testPushEdge() {
Invoice i = zii.extractInvoice();

assertEquals("abc123", i.getInvoiceReferencedDocumentID());
assertEquals(1, i.getInvoiceReferencedDocuments().size());
assertEquals("abcd1234", i.getInvoiceReferencedDocuments().get(0).getIssuerAssignedID());
assertEquals("4304171000002", i.getRecipient().getGlobalID());
assertEquals("2001015001325", i.getZFItems()[0].getProduct().getGlobalID());
assertEquals(orgID, i.getSender().getID());
Expand Down