Skip to content

Commit

Permalink
added tradeLineItems (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
rsoika committed Dec 26, 2024
1 parent 01985de commit 5375130
Show file tree
Hide file tree
Showing 4 changed files with 343 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public abstract class EInvoiceModel {
protected BigDecimal taxTotalAmount = new BigDecimal("0.00");
protected BigDecimal netTotalAmount = new BigDecimal("0.00");
protected Set<TradeParty> tradeParties = null;
protected Set<TradeLineItem> tradeLineItems = null;

private final Map<EInvoiceNS, String> URI_BY_NAMESPACE = new HashMap<>();
private final Map<EInvoiceNS, String> PREFIX_BY_NAMESPACE = new HashMap<>();
Expand All @@ -66,6 +67,7 @@ public abstract class EInvoiceModel {
public EInvoiceModel(Document doc) {
// this();
tradeParties = new LinkedHashSet<>();
tradeLineItems = new LinkedHashSet<>();

if (doc != null) {
this.doc = doc;
Expand Down Expand Up @@ -184,6 +186,62 @@ public TradeParty findTradeParty(String type) {
return null;
}

/**
* Returns all trade line items
*
* @return
*/
public Set<TradeLineItem> getTradeLineItems() {
if (tradeLineItems == null) {
tradeLineItems = new LinkedHashSet<TradeLineItem>();
}
return tradeLineItems;
}

/**
* Adds a new Trade line item. If a item with this id already exists, the method
* removes first the existing item.
*
* @param item
*/
public void setTradeLineItem(TradeLineItem item) {

if (item == null) {
return;
}

// Remove existing items of same id (if exists)
TradeLineItem existingItem = findTradeLineItem(item.getId());
if (existingItem != null) {
tradeLineItems.remove(existingItem);
}

// Add new party
tradeLineItems.add(item);
}

/**
* Finds a Trade line item by its id. Method can return null if not trade line
* item of the id is defined in the invoice
*
* @param id
* @return
*/
public TradeLineItem findTradeLineItem(String id) {
if (id == null || id.isEmpty()) {
return null;
}
Iterator<TradeLineItem> items = getTradeLineItems().iterator();
while (items.hasNext()) {
TradeLineItem item = items.next();
if (id.equals(item.getId())) {
return item;
}
}
// not found
return null;
}

/**
* This helper method returns a set of child nodes by name from a given parent
* node. If no nodes were found, the method returns an empty list.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashSet;
import java.util.Set;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
Expand Down Expand Up @@ -182,6 +184,9 @@ private void loadDocumentCoreData() {
}
}

// read line items...
parseTradeLineItems();

}

public TradeParty parseTradeParty(Element tradePartyElement, String type) {
Expand Down Expand Up @@ -232,6 +237,98 @@ public TradeParty parseTradeParty(Element tradePartyElement, String type) {
return tradeParty;
}

/**
* Parse the trade line items and return a list of items collected
*
* @return
*/
public Set<TradeLineItem> parseTradeLineItems() {
Set<TradeLineItem> items = new LinkedHashSet<>();

Set<Element> lineItems = findChildNodesByName(supplyChainTradeTransaction, EInvoiceNS.RAM,
"IncludedSupplyChainTradeLineItem");

for (Element lineItem : lineItems) {
// Get Line ID
Element docLine = findChildNodeByName(lineItem, EInvoiceNS.RAM, "AssociatedDocumentLineDocument");
if (docLine == null)
continue;

Element idElement = findChildNodeByName(docLine, EInvoiceNS.RAM, "LineID");
if (idElement == null)
continue;

TradeLineItem item = new TradeLineItem(idElement.getTextContent());

// Product details
Element product = findChildNodeByName(lineItem, EInvoiceNS.RAM, "SpecifiedTradeProduct");
if (product != null) {
Element nameElement = findChildNodeByName(product, EInvoiceNS.RAM, "Name");
if (nameElement != null) {
item.setName(nameElement.getTextContent());
}
Element descElement = findChildNodeByName(product, EInvoiceNS.RAM, "Description");
if (descElement != null) {
item.setDescription(descElement.getTextContent());
}
}

// Price info
Element agreement = findChildNodeByName(lineItem, EInvoiceNS.RAM, "SpecifiedLineTradeAgreement");
if (agreement != null) {
Element grossPrice = findChildNodeByName(agreement, EInvoiceNS.RAM, "GrossPriceProductTradePrice");
if (grossPrice != null) {
Element amount = findChildNodeByName(grossPrice, EInvoiceNS.RAM, "ChargeAmount");
if (amount != null) {
item.setGrossPrice(Double.parseDouble(amount.getTextContent()));
}
}

Element netPrice = findChildNodeByName(agreement, EInvoiceNS.RAM, "NetPriceProductTradePrice");
if (netPrice != null) {
Element amount = findChildNodeByName(netPrice, EInvoiceNS.RAM, "ChargeAmount");
if (amount != null) {
item.setNetPrice(Double.parseDouble(amount.getTextContent()));
}
}
}

// Quantity
Element delivery = findChildNodeByName(lineItem, EInvoiceNS.RAM, "SpecifiedLineTradeDelivery");
if (delivery != null) {
Element quantity = findChildNodeByName(delivery, EInvoiceNS.RAM, "BilledQuantity");
if (quantity != null) {
item.setQuantity(Double.parseDouble(quantity.getTextContent()));
}
}

// VAT and total
Element settlement = findChildNodeByName(lineItem, EInvoiceNS.RAM, "SpecifiedLineTradeSettlement");
if (settlement != null) {
Element tax = findChildNodeByName(settlement, EInvoiceNS.RAM, "ApplicableTradeTax");
if (tax != null) {
Element rate = findChildNodeByName(tax, EInvoiceNS.RAM, "RateApplicablePercent");
if (rate != null) {
item.setVat(Double.parseDouble(rate.getTextContent()));
}
}

Element summation = findChildNodeByName(settlement, EInvoiceNS.RAM,
"SpecifiedTradeSettlementLineMonetarySummation");
if (summation != null) {
Element total = findChildNodeByName(summation, EInvoiceNS.RAM, "LineTotalAmount");
if (total != null) {
item.setTotal(Double.parseDouble(total.getTextContent()));
}
}
}

items.add(item);
}

return items;
}

@Override
public void setNetTotalAmount(BigDecimal value) {
// Finde das SpecifiedTradeSettlementHeaderMonetarySummation Element
Expand Down Expand Up @@ -353,4 +450,87 @@ public void setTradeParty(TradeParty newParty) {
}
}
}

/**
* Adds a new TradeLineItem into the XML tree.
*
* @param item
*/
public void addTradeLineItem(TradeLineItem item) {
Element lineItem = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "IncludedSupplyChainTradeLineItem");

// Document Line with ID
Element docLine = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "AssociatedDocumentLineDocument");
Element lineId = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "LineID");
lineId.setTextContent(item.getId());
docLine.appendChild(lineId);
lineItem.appendChild(docLine);

// Product details
Element product = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "SpecifiedTradeProduct");
if (item.getName() != null) {
Element name = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "Name");
name.setTextContent(item.getName());
product.appendChild(name);
}
if (item.getDescription() != null) {
Element desc = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "Description");
desc.setTextContent(item.getDescription());
product.appendChild(desc);
}
lineItem.appendChild(product);

// Trade Agreement (Prices)
Element agreement = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "SpecifiedLineTradeAgreement");

Element grossPrice = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "GrossPriceProductTradePrice");
Element grossAmount = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "ChargeAmount");
grossAmount.setTextContent(String.valueOf(item.getGrossPrice()));
grossPrice.appendChild(grossAmount);
agreement.appendChild(grossPrice);

Element netPrice = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "NetPriceProductTradePrice");
Element netAmount = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "ChargeAmount");
netAmount.setTextContent(String.valueOf(item.getNetPrice()));
netPrice.appendChild(netAmount);
agreement.appendChild(netPrice);

lineItem.appendChild(agreement);

// Trade Delivery (Quantity)
Element delivery = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "SpecifiedLineTradeDelivery");
Element quantity = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "BilledQuantity");
quantity.setAttribute("unitCode", "C62"); // Standard unit code
quantity.setTextContent(String.valueOf(item.getQuantity()));
delivery.appendChild(quantity);
lineItem.appendChild(delivery);

// Trade Settlement (VAT and Total)
Element settlement = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "SpecifiedLineTradeSettlement");

Element tax = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "ApplicableTradeTax");
Element typeCode = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "TypeCode");
typeCode.setTextContent("VAT");
Element categoryCode = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "CategoryCode");
categoryCode.setTextContent("S");
Element rate = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "RateApplicablePercent");
rate.setTextContent(String.valueOf(item.getVat()));
tax.appendChild(typeCode);
tax.appendChild(categoryCode);
tax.appendChild(rate);
settlement.appendChild(tax);

Element summation = getDoc()
.createElement(getPrefix(EInvoiceNS.RAM) + "SpecifiedTradeSettlementLineMonetarySummation");
Element total = getDoc().createElement(getPrefix(EInvoiceNS.RAM) + "LineTotalAmount");
total.setTextContent(String.valueOf(item.getTotal()));
summation.appendChild(total);
settlement.appendChild(summation);

lineItem.appendChild(settlement);

// Add to supplyChainTradeTransaction
supplyChainTradeTransaction.appendChild(lineItem);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package org.imixs.archive.documents.einvoice;

/**
* A TradeParty is a container for a TradeParty element
*
* @author rsoika
*
*/
public class TradeLineItem {

private String id;
private String name;
private String description;
private double grossPrice;
private double netPrice;
private double quantity;
private double vat;
private double total;

public TradeLineItem(String id) {
this.id = id;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public double getGrossPrice() {
return grossPrice;
}

public void setGrossPrice(double grossPrice) {
this.grossPrice = grossPrice;
}

public double getNetPrice() {
return netPrice;
}

public void setNetPrice(double netPrice) {
this.netPrice = netPrice;
}

public double getQuantity() {
return quantity;
}

public void setQuantity(double quantity) {
this.quantity = quantity;
}

public double getVat() {
return vat;
}

public void setVat(double vat) {
this.vat = vat;
}

public double getTotal() {
return total;
}

public void setTotal(double total) {
this.total = total;
}

// toString method for easy debugging
@Override
public String toString() {
return "TradeLineItem{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", grossPrice='" + grossPrice + '\'' +
", netPrice='" + netPrice + '\'' +
", quantity='" + quantity + '\'' +
", vat='" + vat + '\'' +
", total='" + total + '\'' +
'}';
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ public void setVatNumber(String vatNumber) {
// toString method for easy debugging
@Override
public String toString() {
return "SellerTradeParty{" +
"name='" + name + '\'' +
return "TradeParty{" +
"type='" + type + '\'' +
", name='" + name + '\'' +
", postcodeCode='" + postcodeCode + '\'' +
", streetAddress='" + streetAddress + '\'' +
", cityName='" + cityName + '\'' +
Expand Down

0 comments on commit 5375130

Please sign in to comment.