CostingUtils.java
package com.tradecloud.domain.costing.utils;
import com.tradecloud.domain.CommissionInformation;
import com.tradecloud.domain.costing.CostGroup;
import com.tradecloud.domain.costing.CostLine;
import com.tradecloud.domain.costing.CostLinePayerType;
import com.tradecloud.domain.costing.CostLineTemplate;
import com.tradecloud.domain.costing.clean.*;
import com.tradecloud.domain.document.invoice.ActualLineItem;
import com.tradecloud.domain.document.invoice.CalculatedCostingCell;
import com.tradecloud.domain.document.invoice.CostLineCostingCell;
import com.tradecloud.domain.document.invoice.CostingCell;
import com.tradecloud.domain.exchangerate.DefaultRateOfExchanges;
import com.tradecloud.domain.exchangerate.RateOfExchanges;
import com.tradecloud.domain.item.LineItem;
import com.tradecloud.domain.model.ordermanagement.Consignment;
import com.tradecloud.domain.model.ordermanagement.Order;
import com.tradecloud.domain.shipment.Shipment;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.*;
@Component("costingUtils")
public class CostingUtils {
public static Logger log = Logger.getLogger(CostingUtils.class);
/**
* Add a specified amount to the transaction and costing currency totals.
*
* @param costLineSummary The cost line summary to add amount to totals
* @param transactionCurrencyAmountToAdd The transaction currency amount to add
*/
public static void addToTotals(CostLineSummary costLineSummary, BigDecimal transactionCurrencyAmountToAdd) {
// Add the sub transactionCurrencyTotal
costLineSummary.setTransactionCurrencyTotal(costLineSummary.getTransactionCurrencyTotal().add(transactionCurrencyAmountToAdd));
// Shouldn't round up on individual LineItem, should only round the costingCurrencyTotal CostLine result
BigDecimal costingCurrencyAmountToAdd;
if (costLineSummary.getForwardRate() != null) {
costingCurrencyAmountToAdd = transactionCurrencyAmountToAdd.multiply(costLineSummary.getForwardRate());
} else {
costingCurrencyAmountToAdd = transactionCurrencyAmountToAdd;
}
// Add the sub costingCurrencyTotal
costLineSummary.setCostingCurrencyTotal(costLineSummary.getCostingCurrencyTotal().add(costingCurrencyAmountToAdd));
// log.debug("New costline transaction currency total=" + costLineSummary.getTransactionCurrencyTotal() + ". New cost line costing currency "
// + "total= " + costLineSummary.getCostingCurrencyTotal());
}
/**
* Creates a map of direct costs totals for each cost group.
*
* @param costingSummary
* @return
*/
public static Map<CostGroup, BigDecimal> createDirectCostGroupTotalsMap(CostingSummary costingSummary) {
return createCostGroupTotalsMap(costingSummary, CostLinePayerType.EXPORTER);
}
/**
* Creates a map of indirect costs totals for each cost group.
*
* @param costingSummary
* @return
*/
public static Map<CostGroup, BigDecimal> createIndirectCostGroupTotalsMap(CostingSummary costingSummary) {
return createCostGroupTotalsMap(costingSummary, CostLinePayerType.IMPORTER);
}
/**
* Creates a map of totals of direct or indirect costs for each cost group.
*
* @param costingSummary
* @param costLinePayerType Either Importer or Exporter
* @return
*/
public static Map<CostGroup, BigDecimal> createCostGroupTotalsMap(CostingSummary<?, ?> costingSummary, CostLinePayerType costLinePayerType) {
Map<CostGroup, BigDecimal> costGroupTotalsMap = new EnumMap<>(CostGroup.class);
if (costingSummary.getCostLineSummaries() != null) {
for (CostLineSummary costLineSummary : costingSummary.getCostLineSummaries()) {
if (costLineSummary.getCostLine().isBaseSupply()) {
continue;
}
CostLine costLine = costLineSummary.getCostLine();
// if a costLinePayerType was not passed then build a map of direct and indirect cost lines
// if a costLinePayerType was passed only worry about cost lines that match the provided CostLinePayerType IMPORTER/EXPORTER param
if (costLinePayerType == null || costLinePayerType.equals(costLine.getCostLinePayerType())) {
CostGroup costGroup = costLineSummary.getCostLine().getCostLineTemplate().getCostGroup();
// cost group totals map
if (costGroupTotalsMap.containsKey(costGroup)) {
BigDecimal currentCostGroupTotal = costGroupTotalsMap.get(costGroup);
currentCostGroupTotal = currentCostGroupTotal.add(costLineSummary.getCostingCurrencyTotal());
// replace the cost group total in the map
costGroupTotalsMap.put(costGroup, currentCostGroupTotal);
} else {
BigDecimal currentCostGroupTotal = costLineSummary.getCostingCurrencyTotal();
costGroupTotalsMap.put(costGroup, currentCostGroupTotal);
}
}
}
}
return costGroupTotalsMap;
}
/**
* Creates a map of direct costs from cost group to their cost lines.
*
* @param costingSummary
* @return
*/
public static Map<CostGroup, List<CostLineSummary>> createDirectCostGroupCostLineSummariesMap(CostingSummary costingSummary) {
return createCostGroupCostLineSummariesMap(costingSummary, CostLinePayerType.EXPORTER);
}
/**
* Creates a map of indirect costs from cost group to their cost lines.
*
* @param costingSummary
* @return
*/
public static Map<CostGroup, List<CostLineSummary>> createIndirectCostGroupCostLineSummariesMap(CostingSummary costingSummary) {
return createCostGroupCostLineSummariesMap(costingSummary, CostLinePayerType.IMPORTER);
}
/**
* Creates a map of direct costs from cost group to their cost lines using the costLineCosting.
*
* @param costLineCosting
* @return
*/
public static Map<CostGroup, List<CostLineSummary>> createDirectCostGroupCostLineSummariesMap(CostLineCosting costLineCosting) {
return createCostGroupCostLineSummariesMap(costLineCosting, CostLinePayerType.EXPORTER);
}
/**
* Creates a map of indirect costs from cost group to their cost lines using the costLineCosting.
*
* @param costLineCosting
* @return
*/
public static Map<CostGroup, List<CostLineSummary>> createIndirectCostGroupCostLineSummariesMap(CostLineCosting costLineCosting) {
return createCostGroupCostLineSummariesMap(costLineCosting, CostLinePayerType.IMPORTER);
}
/**
* Creates a map of direct or indirect costs from cost group to their cost lines.
*
* @param costingSummary
* @param costLinePayerType Either Importer or Exporter
* @return
*/
private static Map<CostGroup, List<CostLineSummary>> createCostGroupCostLineSummariesMap(CostingSummary<?, ?> costingSummary,
CostLinePayerType costLinePayerType) {
Map<CostGroup, List<CostLineSummary>> costLinesMap = new EnumMap<>(CostGroup.class);
if (costingSummary.getCostLineSummaries() != null) {
for (CostLineSummary costLineSummary : costingSummary.getCostLineSummaries()) {
CostLine costLine = costLineSummary.getCostLine();
// only worry about cost lines that match the provided CostLinePayerType IMPORTER/EXPORTER param
if (costLinePayerType != null && costLinePayerType.equals(costLine.getCostLinePayerType()) && !costLine.isBaseSupply()) {
CostGroup costGroup = costLine.getCostLineTemplate().getCostGroup();
// cost lines map
if (costLinesMap.containsKey(costGroup)) {
List<CostLineSummary> list = costLinesMap.get(costGroup);
if (!list.contains(costLineSummary)) {
list.add(costLineSummary);
}
} else {
List<CostLineSummary> newList = new ArrayList<>();
newList.add(costLineSummary);
costLinesMap.put(costGroup, newList);
}
Collections.sort(costLinesMap.get(costGroup), new CostLineSummaryDisplayComparator());
}
}
}
return costLinesMap;
}
/**
* Creates a map of direct or indirect costs from cost group to their cost lines using the cost line costing.
*
* @param costLineCosting
* @param costLinePayerType Either Importer or Exporter
* @return
*/
private static Map<CostGroup, List<CostLineSummary>> createCostGroupCostLineSummariesMap(CostLineCosting costLineCosting,
CostLinePayerType costLinePayerType) {
Map<CostGroup, List<CostLineSummary>> costLinesMap = new EnumMap<>(CostGroup.class);
if (costLineCosting.getCostLineCostingCells() != null) {
for (CostLineCostingCell costLineCostingCell : costLineCosting.getCostLineCostingCells()) {
CostLineSummary costLineSummary = new CostLineSummary();
costLineSummary.setCostLine(costLineCostingCell.getCostLine());
costLineSummary.setForwardRate(costLineCostingCell.getForwardRate());
costLineSummary.setTransactionCurrency(costLineCostingCell.getTransactionCurrency());
costLineSummary.setCostPercentage(costLineCostingCell.getPercentage());
if (costLineCostingCell.getTransactionAmount() != null && costLineCostingCell.getForwardRate() != null) {
costLineSummary.setCostingCurrencyTotal(costLineCostingCell.getTransactionAmount()
.multiply(costLineCostingCell.getForwardRate()));
}
costLineSummary.setTransactionCurrencyTotal(costLineCostingCell.getTransactionAmount());
CostLine costLine = costLineCostingCell.getCostLine();
// only worry about cost lines that match the provided CostLinePayerType IMPORTER/EXPORTER param
if (costLinePayerType != null && costLinePayerType.equals(costLine.getCostLinePayerType()) && !costLine.isBaseSupply()) {
CostGroup costGroup = costLine.getCostLineTemplate().getCostGroup();
// cost lines map
if (costLinesMap.containsKey(costGroup)) {
List<CostLineSummary> list = costLinesMap.get(costGroup);
if (!list.contains(costLineSummary)) {
list.add(costLineSummary);
}
} else {
List<CostLineSummary> newList = new ArrayList<>();
newList.add(costLineSummary);
costLinesMap.put(costGroup, newList);
}
Collections.sort(costLinesMap.get(costGroup), new CostLineSummaryDisplayComparator());
}
}
}
return costLinesMap;
}
/**
* Maps the costlines according to their cost group.
*
* @param costLines
* @return
*/
public static Map<CostGroup, List<CostLine>> createCostGroupCostLineMap(Collection<CostLine> costLines) {
Map<CostGroup, List<CostLine>> map = new EnumMap<>(CostGroup.class);
// TODO. Inefficient. loops through the cost lines many times
for (CostGroup costGroup : CostGroup.values()) {
for (CostLine costLine : costLines) {
if (costGroup == costLine.getCostLineTemplate().getCostGroup()) {
if (!map.containsKey(costGroup)) {
List<CostLine> list = new ArrayList<>();
list.add(costLine);
map.put(costGroup, list);
}
if (map.containsKey(costGroup) && !map.get(costGroup).contains(costLine)) {
map.get(costGroup).add(costLine);
}
//log.debug(costGroup + " -> " + costLine.getCostLineTemplate());
}
}
}
return map;
}
public static Map<CostGroup, List<String>> createCostGroupCostLineNameMap(Collection<CostLine> costLines) {
Map<CostGroup, List<String>> map = new EnumMap<>(CostGroup.class);
for (CostLine costLine : costLines) {
CostGroup costGroup = costLine.getCostLineTemplate().getCostGroup();
String name = costLine.getCostLineTemplate().getName();
if (!map.containsKey(costGroup)) {
List<String> list = new ArrayList<>();
list.add(name);
map.put(costGroup, list);
}
if (map.containsKey(costGroup) && !map.get(costGroup).contains(name)) {
map.get(costGroup).add(name);
}
//log.debug(costGroup + " -> " + costLine.getCostLineTemplate());
}
return map;
}
public static Costed findRootParent(Costed costed) {
if (costed.getParent() == null) {
return costed;
}
return findRootParent(costed.getParent());
}
/**
* Filters out costline not of the payer type.
*
* @param costLines
* @param costLinePayerType
* @return
*/
public static Collection<CostLine> filterCostLinePayerType(Collection<CostLine> costLines, CostLinePayerType costLinePayerType) {
Collection<CostLine> filteredCostLines = new HashSet<>();
for (CostLine costLine : costLines) {
if (costLine.getCostLinePayerType() == costLinePayerType) {
filteredCostLines.add(costLine);
}
}
return filteredCostLines;
}
public static List<CostLine> filterRemoveCostGroup(Collection<CostLine> costLines, CostGroup costGroup) {
List<CostLine> withoutCostGroup = new ArrayList<>();
for (CostLine costLine : costLines) {
if (!costLine.getCostLineTemplate().getCostGroup().equals(costGroup)) withoutCostGroup.add(costLine);
}
return withoutCostGroup;
}
/**
* Query method to return flag to indicate if this cost line is a discount cost line, this means the value will be displayed as a negative one on
* the Estimate Cost Summary page e.g. Explicitly only the EXWorks : Discount cost line is a discount at time of implementation - request to not
* be configurable. {@link https://jira.devstream.net/browse/BTM-863} Costing: Discount should be a negative value} Hard-coded check based on the
* cost line name as requested {@link https://jira.devstream.net/browse/BTM-863?focusedCommentId=58751}
*
* @param costLine
* @return true if cost line is EXWorks : Discount cost line return true. Otherwise, false.
*/
public static boolean isDiscountCost(CostLine costLine) {
// return CostLineNames.EXWORKS_DISCOUNT.equals(costLine.getCostLineTemplate().getCode());
return costLine.getCostLineTemplate().isDiscount();
}
/**
* Create CostLineCostingCell for each of the supplied cost lines.
*
* @param costLines
* @param spotRate
* @param forwardRate
* @return
*/
// Use the RateOfExchanges version
@Deprecated
public static List<CostLineCostingCell> createCostLineCostingCells(Collection<CostLine> costLines, BigDecimal spotRate, BigDecimal forwardRate) {
List<CostLineCostingCell> costLineCostingCells = new ArrayList<>();
for (CostLine costLine : costLines) {
CostLineCostingCell costLineCostingCell = createCostLineCostingCell(spotRate, forwardRate, costLine);
costLineCostingCells.add(costLineCostingCell);
}
return costLineCostingCells;
}
// Use the RateOfExchanges version
@Deprecated
public static CostLineCostingCell createCostLineCostingCell(BigDecimal spotRate, BigDecimal forwardRate, CostLine costLine) {
DefaultRateOfExchanges rateOfExchanges = new DefaultRateOfExchanges(spotRate, forwardRate);
return createCostLineCostingCell(costLine, rateOfExchanges);
}
public static List<CostLineCostingCell> createCostLineCostingCells(Collection<CostLine> costLines, RateOfExchanges rateOfExchanges,
boolean primaryCosting) {
List<CostLineCostingCell> costLineCostingCells = new ArrayList<>();
for (CostLine costLine : costLines) {
CostLineCostingCell costLineCostingCell = createCostLineCostingCell(costLine, rateOfExchanges);
costLineCostingCell.setPrimaryCosting(primaryCosting);
costLineCostingCells.add(costLineCostingCell);
}
return costLineCostingCells;
}
public static CostLineCostingCell createCostLineCostingCell(CostLine costLine, RateOfExchanges rateOfExchanges) {
CostLineCostingCell costLineCostingCell = new CostLineCostingCell();
costLineCostingCell.setCostLine(costLine);
costLineCostingCell.setForwardRate(rateOfExchanges.getForwardRate());
costLineCostingCell.setSpotRate(rateOfExchanges.getSpotRate());
costLineCostingCell.setTransactionCurrency(costLine.getTransactionCurrency());
costLineCostingCell.setDutiable(costLine.isDutiable());
costLineCostingCell.setVatType(costLine.getVatType());
return costLineCostingCell;
}
/**
* Delete the related costLineCostingCells for the supplied cost lines.
*
* @param costLineCostingCells
* @param costLines
*/
public static void deleteCostLineCostingCells(Collection<CostLineCostingCell> costLineCostingCells, Collection<CostLine> costLines) {
Collection<CostLineCostingCell> toDelete = new ArrayList<>();
for (CostLineCostingCell costLineCostingCell : costLineCostingCells) {
if (costLines.contains(costLineCostingCell.getCostLine())) {
toDelete.add(costLineCostingCell);
}
}
costLineCostingCells.removeAll(toDelete);
}
public static List<CalculatedCostingCell> createCalculatedAmounts(Collection<CostLine> costLines) {
List<CalculatedCostingCell> calculatedAmounts = new ArrayList<>();
for (CostLine costLine : costLines) {
CalculatedCostingCell calculatedAmount = new CalculatedCostingCell();
calculatedAmount.setCostLine(costLine);
calculatedAmounts.add(calculatedAmount);
}
return calculatedAmounts;
}
public static List<CostLine> addElcCostlines(CostGroup costGroup1) {
List<CostLine> elcCostlines = new ArrayList<>();
String name = "name";
String code = "code";
elcCostlines.add(getCostLine("ELC Unit cost", costGroup1.name() + "." + ElcGlcVarianceType.ELCUnitcost.name()));
elcCostlines.add(getCostLine("ELC CLC Variance", costGroup1.name() + "." + ElcGlcVarianceType.ELCGLCVariance.name()));
elcCostlines.add(getCostLine("ELC Item Cost", costGroup1.name() + "." + ElcGlcVarianceType.ELCItemCost.name()));
elcCostlines.add(getCostLine("ELC CLC Item Variance", costGroup1.name() + "." + ElcGlcVarianceType.ELCGLCItemVariance.name()));
return elcCostlines;
}
private static CostLine getCostLine(String name, String code) {
CostLineTemplate template = new CostLineTemplate();
template.setCode(code);
template.setName(name);
return new CostLine(template);
}
public BigDecimal getCostingCurrencyTotalCost(List<CostLineSummary> costLineSummaries, String costTypeCode) {
CostLineSummary costLineSummary = getCostLineSummary(costLineSummaries, costTypeCode);
if (costLineSummary != null) {
return costLineSummary.getCostingCurrencyTotal();
}
log.error("No cost line costingCurrencyTotal found with costTypeCode:" + costTypeCode);
return null;
}
public CostLineSummary getCostLineSummary(List<CostLineSummary> costLineSummaries, String costTypeCode) {
for (CostLineSummary costLineSummary : costLineSummaries) {
if (costLineSummary.getCostLine().getCostLineTemplate().getCode().equals(costTypeCode)) {
return costLineSummary;
}
}
log.error("No cost line costingCurrencyTotal found with costTypeCode:" + costTypeCode);
return null;
}
/**
* Want to discourage use of this, hence its private scope - {@link CostingSummary#lookupCosting(java.lang.String)} instead.
*
* @param costingSummary
* @param costTypeCode
* @return
* @deprecated
*/
private CostLineSummary getCostLineSummary(CostingSummary costingSummary, String costTypeCode) {
return costingSummary.lookupCosting(costTypeCode);
}
public static BigDecimal getCostLineAmount(String costLineCode, Costed costed1) {
BigDecimal money = getCachedAmount(costed1, costLineCode);
if (money.doubleValue() == 0.0) {
money = getCachedCalculatedAmount(costed1, costLineCode);
}
if (money.doubleValue() == 0.0) {
money = getCalculatedAmount(costed1, costLineCode);
}
if (money == null || money.doubleValue() == 0.0) {
money = getCostLineCostingAmount(costed1, costLineCode);
}
return money;
}
private static BigDecimal getCostLineCostingAmount(Costed costed, String costLineCode) {
final CostingCell costingCell = costed.getCostLineCosting().getCostingCell(costLineCode);
return costingCell == null ? null : costingCell.getTransactionAmount();
}
private static BigDecimal getCalculatedAmount(Costed costed, String costLineName) {
final CostingCell cachedCalculatedCostingCell = costed.getCostLineCosting().getCalculatedCostingCell(costLineName);
return cachedCalculatedCostingCell == null ? null : cachedCalculatedCostingCell.getTransactionAmount();
}
private static BigDecimal getCachedCalculatedAmount(Costed costed, String costLineName) {
final CostingCell cachedCalculatedCostingCell = costed.getCostLineCosting().getCachedCalculatedCostingCell(costLineName);
if (cachedCalculatedCostingCell != null) {
return cachedCalculatedCostingCell.getTransactionAmount();
} else {
return BigDecimal.ZERO;
}
}
private static BigDecimal getCachedAmount(Costed costed, String costLineName) {
final CostingCell cachedCostingCell = costed.getCostLineCosting().getCachedCostLineCostingCell(costLineName);
if (cachedCostingCell != null) {
return cachedCostingCell.getTransactionAmount();
} else {
return BigDecimal.ZERO;
}
}
public static CostLine createDutiableCostCostLine() {
CostLineTemplate dutiableCostLine = new CostLineTemplate();
dutiableCostLine.setCode(CostingUtils.CALCULATED_DUTIABLE_COST_CODE);
dutiableCostLine.setName(CostingUtils.CALCULATED_DUTIABLE_COST_NAME);
CostLine calculatedDutiableCostLine = new CostLine(dutiableCostLine);
return calculatedDutiableCostLine;
}
public static BigDecimal getAgentCommissionPercentage(Costed costed, BigDecimal defaultRate, CostLineSummary costLineSummary,
CostingSummary costingSummary) {
Costed costedLineItem = findFirstCostedLineItem(costed);
if (costedLineItem != null) {
LineItem lineItem = getLineItem(costedLineItem, costingSummary);
String costLineCode = costLineSummary.getCostLine().getCostLineTemplate().getCode();
CommissionInformation commissionInfo = lineItem.getCommissionInformation();
switch (costLineCode) {
case CostLineNames.AGENT_FOREIGN_COMMISSION:
return getNotNull(commissionInfo.getForeignCommissionPercentage(),
commissionInfo.getDefaultForeignCommissionPercentage(), defaultRate);
case CostLineNames.AGENT_SOURCING_COMMISSION:
return getNotNull(commissionInfo.getSourcingCommissionPercentage(),
commissionInfo.getDefaultSourcingCommissionPercentage(), defaultRate);
case CostLineNames.AGENT_WAREHOUSING_COMMISSION:
return getNotNull(commissionInfo.getWarehousingCommissionPercentage(),
commissionInfo.getDefaultWarehousingCommissionPercentage(), defaultRate);
case CostLineNames.AGENT_MERCHANDISING_COMMISSION:
return getNotNull(commissionInfo.getMerchandisingCommissionPercentage(),
commissionInfo.getDefaultMerchandisingCommissionPercentage(), defaultRate);
default:
break;
}
}
return defaultRate;
}
public static LineItem getLineItem(Costed costed, CostingSummary costingSummary) {
if (costingSummary instanceof InvoiceCostingSummary || costingSummary instanceof ActualCostSummary) {
return getLineItemFromShipment(costingSummary.getShipment(), ((ActualLineItem) costed).getOriginalId());
} else {
return ((CostedLineItem) costed).getLineItem();
}
}
public static LineItem getLineItemFromShipment(Shipment shipment, Long originalId) {
for (Consignment consignment : shipment.getActiveConsignments()) {
for (Order order : consignment.getActiveOrders()) {
for (LineItem lineItem : order.getActiveLineItems()) {
if (lineItem.getId().equals(originalId)) {
return lineItem;
}
}
}
}
return null;
}
// Do not like this! Traverses the whole shipment for nothing.
// But might be more efficient than the above method
public static LineItem getLineItemFromShipment(Shipment shipment, Long consignmentId, Long lineItemId) {
for (Consignment activeConsignment : shipment.getActiveConsignments()) {
if (activeConsignment.getId().equals(consignmentId)) {
for (Order activeOrder : activeConsignment.getActiveOrders()) {
if (activeOrder.getId().equals(activeOrder.getId())) {
for (LineItem lineItem : activeOrder.getActiveLineItems()) {
if (lineItem.getId().equals(lineItemId)) {
return lineItem;
}
}
}
}
}
}
return null;
}
private static BigDecimal getNotNull(BigDecimal... bigDecimals) {
for (BigDecimal bigDecimal : bigDecimals) {
if (bigDecimal != null) {
return bigDecimal;
}
}
return null;
}
public static Costed findFirstCostedLineItem(Costed<? extends Costed, ? extends Costed> costed) {
if (costed != null) {
if (costed instanceof CostedLineItem || costed instanceof ActualLineItem) {
return costed;
} else {
for (Costed child : costed.getCostedChildren()) {
return findFirstCostedLineItem(child);
}
}
}
return null;
}
public static Costed findCostedOrderOrActualOrder(Costed costed) {
if (costed.isItem())
return costed.getParent();
if (costed.isOrder())
return costed;
return null;
}
//[0]: spot, [1]: forward
public static RateOfExchanges findSpotAndForward(Costed costed, CostLineSummary costLineSummary, boolean rateFeed) {
String costLineCode = costLineSummary.getCostLine().getCostLineTemplate().getCode();
RateOfExchanges spotAndForward = new DefaultRateOfExchanges(costLineSummary.getSpotRate(), costLineSummary.getForwardRate());
Costed theOrder = findCostedOrderOrActualOrder(costed);
if (theOrder != null) {
CostingCell cell = theOrder.getCostLineCosting().getCachedCostLineCostingCell(costLineCode);
if (cell != null) {
BigDecimal spotRate = rateFeed ? cell.getRateFeedSpotRate() : cell.getSpotRate();
BigDecimal forwardRate = rateFeed ? cell.getRateFeedForwardRate() : cell.getForwardRate();
if (spotRate != null) {
spotAndForward.setSpotRate(spotRate);
}
if (forwardRate != null) {
spotAndForward.setForwardRate(forwardRate);
}
}
}
return spotAndForward;
}
public static Costed getCostedOrderInStructure(Costed costed, Order order) {
return findCostedOrderFromOrderInStructure(costed, order);
}
public static Costed findCostedOrderFromOrderInStructure(Costed costed, Order order) {
if (CostingStructureMatcher.match(order, costed))
//if (order.match(costed))
return costed;
Costed costedOrder = lookForOrderInParents(costed, order);
if (costedOrder == null)
costedOrder = lookForOrderInChildren(findRootParent(costed), order);
return costedOrder;
}
public static Costed findActualInActualStructureMatchingEstimate(Costed actualParent, Costed estimate) {
if (CostingStructureMatcher.match(estimate, actualParent))
return actualParent;
Costed costed = lookForOrderInChildren(actualParent, estimate);
return costed;
}
private static Costed lookForOrderInChildren(Costed<? extends Costed, ? extends Costed> parent,
Costed<? extends Costed, ? extends Costed> lookFor) {
if (parent.getCostedChildren() == null || parent.getCostedChildren().isEmpty())
return null;
Costed found = null;
for (Costed child : parent.getCostedChildren()) {
if (CostingStructureMatcher.match(lookFor, child)) {
found = child;
} else {
found = lookForOrderInChildren(child, lookFor);
}
if (found != null)
break;
}
return found;
}
private static Costed lookForOrderInChildren(Costed<? extends Costed, ? extends Costed> parent, Order order) {
if (parent.getCostedChildren() == null || parent.getCostedChildren().isEmpty())
return null;
Costed found = null;
for (Costed child : parent.getCostedChildren()) {
if (CostingStructureMatcher.match(order, child)) {
//if (order.match(child)) {
found = child;
} else {
found = lookForOrderInChildren(child, order);
}
if (found != null)
break;
}
return found;
}
private static Costed lookForOrderInParents(Costed child, Order order) {
if (child.getParent() == null)
return null;
Costed parent = child.getParent();
if (CostingStructureMatcher.match(order, parent)) {
//if (order.match(parent)) {
return parent;
}
return lookForOrderInParents(parent, order);
}
public static CostedLineItem getCostedLineItem(Costed costed, LineItem lineItem) {
if (costed instanceof CostedLineItem) {
CostedLineItem costedLineItem = (CostedLineItem) costed;
//if (lineItem.match(costedLineItem)) {
if (CostingStructureMatcher.match(lineItem, costedLineItem)) {
return costedLineItem;
}
} else {
for (Object object : costed.getCostedChildren()) {
CostedLineItem costedLineItem = getCostedLineItem((Costed) object, lineItem);
if (costedLineItem != null) {
return costedLineItem;
}
}
}
return null;
}
public static List<LineItem> getLineItems(Consignment consignment) {
List<LineItem> lineItems = new ArrayList<>();
for (Order order : consignment.getOrders()) {
lineItems.addAll(order.getLineItems());
}
return lineItems;
}
public static <T extends Object> void moveOtherCostLineToBeLast(List<T> costLines) {
List<String> otherCostLines = new ArrayList<String>();
otherCostLines.add(CostLineNames.AGENT_OTHER);
otherCostLines.add(CostLineNames.EXWORKS_OTHER);
otherCostLines.add(CostLineNames.FORWARDING_OTHER);
otherCostLines.add(CostLineNames.FREIGHT_OTHER);
otherCostLines.add(CostLineNames.FINANCE_OTHER);
otherCostLines.add(CostLineNames.CLEARING_OTHER);
otherCostLines.add(CostLineNames.CUSTOMS_OTHER);
otherCostLines.add(CostLineNames.INTERNAL_PROVISIONS_OTHER);
T toAdd = null;
for (T costLine : costLines) {
String code = "";
if (costLine instanceof CostLine) {
code = ((CostLine) (costLine)).getCostLineTemplate().getCode();
} else if (costLine instanceof CostLineSummary) {
code = ((CostLineSummary) (costLine)).getCostLine().getCostLineTemplate().getCode();
} else {
throw new RuntimeException("Invalid input, requires CostLine or CostLineSummary.");
}
if (otherCostLines.contains(code)) {
toAdd = costLine;
costLines.remove(costLine);
break;
}
}
if (toAdd != null) costLines.add(toAdd);
}
public static final String CALCULATED_DUTIABLE_COST_CODE = "CALCULATED_DUTIABLE_COST";
public static final String CALCULATED_DUTIABLE_COST_NAME = "Dutiable Cost";
public static final String CALCULATED_CUSTOMS_DUTY_CODE = "CALCULATED_CUSTOMS_DUTY";
public static final String CALCULATED_CUSTOMS_DUTY_NAME = "Calculated Customs Duty";
public static final String CALCULATED_TOTAL_DIRECT_COST_CODE = "CALCULATED_TOTAL_DIRECT_COST_CODE";
public static final String CALCULATED_TOTAL_DIRECT_COST_NAME = "Total Direct Cost";
public static final String CALCULATED_CUSTOMS_VAT = "CALCULATED_CUSTOMS_VAT";
}