CostedTotals.java

package com.tradecloud.domain.costing.clean;

import com.tradecloud.common.base.PersistenceBase;
import com.tradecloud.domain.costing.*;
import com.tradecloud.domain.document.invoice.CostingCell;
import com.tradecloud.domain.exchangerate.RateOfExchanges;
import org.apache.commons.lang3.ObjectUtils;

import javax.persistence.*;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.EnumMap;
import java.util.Map;

@Entity
@Table(name = "costedtotals")
@Access(AccessType.FIELD)
@XmlAccessorType(XmlAccessType.FIELD)
public class CostedTotals extends PersistenceBase {
    private static final long serialVersionUID = 1L;

    @XmlTransient
    //can't resolve this now, making it eager, this map is very lite as it is enum map of BigDecimal.
    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "costedtotals_costapplicationbasis", joinColumns = {@JoinColumn(name = "costedtotals_id")})
    @MapKeyColumn(name = "name")
    @Column(name = "value")
    @MapKeyEnumerated(EnumType.STRING)
    private Map<CostApplicationBasis, BigDecimal> costApplicationBasisCost =
            new EnumMap<CostApplicationBasis, BigDecimal>(CostApplicationBasis.class);

    @XmlTransient
    @ElementCollection
    @CollectionTable(name = "costedtotals_totalimportcostexvatatspot", joinColumns = {@JoinColumn(name = "costedtotals_id")})
    @MapKeyColumn(name = "name")
    @Column(name = "value")
    @MapKeyEnumerated(EnumType.STRING)
    private Map<CostGroup, BigDecimal> totalImportCostExVatAtSpot = new EnumMap<CostGroup, BigDecimal>(CostGroup.class);

    @XmlTransient
    @ElementCollection
    @CollectionTable(name = "costedtotals_totalexportcostexvatatspot", joinColumns = {@JoinColumn(name = "costedtotals_id")})
    @MapKeyColumn(name = "name")
    @Column(name = "value")
    @MapKeyEnumerated(EnumType.STRING)
    private Map<CostGroup, BigDecimal> totalExportCostExVatAtSpot = new EnumMap<CostGroup, BigDecimal>(CostGroup.class);

    @XmlTransient
    @ElementCollection
    @CollectionTable(name = "costedtotals_totalimportcostexvatatforward", joinColumns = {@JoinColumn(name = "costedtotals_id")})
    @MapKeyColumn(name = "name")
    @Column(name = "value")
    @MapKeyEnumerated(EnumType.STRING)
    private Map<CostGroup, BigDecimal> totalImportCostExVatAtForward = new EnumMap<CostGroup, BigDecimal>(CostGroup.class);

    @XmlTransient
    @ElementCollection
    @CollectionTable(name = "costedtotals_totalexportcostexvatatforward", joinColumns = {@JoinColumn(name = "costedtotals_id")})
    @MapKeyColumn(name = "name")
    @Column(name = "value")
    @MapKeyEnumerated(EnumType.STRING)
    private Map<CostGroup, BigDecimal> totalExportCostExVatAtForward = new EnumMap<CostGroup, BigDecimal>(CostGroup.class);

    @XmlElement(name = "totalVat")
    private BigDecimal totalVat = BigDecimal.ZERO;

    @XmlElement(name = "dutiableCost")
    private BigDecimal dutiableCost = BigDecimal.ZERO;

    @XmlElement(name = "dutiableCostAtSpot")
    private BigDecimal dutiableCostAtSpot = BigDecimal.ZERO;

    @XmlElement(name = "dutiableCostAtForward")
    private BigDecimal dutiableCostAtForward = BigDecimal.ZERO;

    @XmlElement(name = "markupPercentExclVat")
    BigDecimal markupPercentExclVat = BigDecimal.ZERO;

    @XmlElement(name = "marginPercentExclVAT")
    BigDecimal marginPercentExclVAT = BigDecimal.ZERO;

    @XmlElement(name = "marginExclVAT")
    BigDecimal marginExclVAT = BigDecimal.ZERO;

    @XmlElement(name = "marginExclVatInclCostToServe")
    BigDecimal marginExclVatInclCostToServe = BigDecimal.ZERO;

    @XmlElement(name = "marginExclVatCostToServe")
    BigDecimal marginExclVatCostToServe = BigDecimal.ZERO;

    @XmlElement(name = "totalRevenueExclVAT")
    BigDecimal totalRevenueExclVAT = BigDecimal.ZERO;

    @XmlElement(name = "markupPercentInclVat")
    BigDecimal markupPercentInclVat = BigDecimal.ZERO;

    @XmlElement(name = "marginPercentInclVAT")
    BigDecimal marginPercentInclVAT = BigDecimal.ZERO;

    @XmlElement(name = "marginInclVAT")
    BigDecimal marginInclVAT = BigDecimal.ZERO;

    @XmlElement(name = "totalRevenueInclVAT")
    BigDecimal totalRevenueInclVAT = BigDecimal.ZERO;

    @XmlElement(name = "elcUnitCostExcVat")
    BigDecimal elcUnitCostExcVat = BigDecimal.ZERO;
    @XmlElement(name = "elcGlcItemVarianceExcVat")
    BigDecimal elcGlcItemVarianceExcVat = BigDecimal.ZERO;
    @XmlElement(name = "elcGlcVarianceExcVat")
    BigDecimal elcGlcVarianceExcVat = BigDecimal.ZERO;
    @XmlElement(name = "elcItemCostExcVat")
    BigDecimal elcItemCostExcVat = BigDecimal.ZERO;

    @XmlElement(name = "elcUnitCostInclVat")
    BigDecimal elcUnitCostInclVat = BigDecimal.ZERO;
    @XmlElement(name = "elcGlcItemVarianceInclVat")
    BigDecimal elcGlcItemVarianceInclVat = BigDecimal.ZERO;
    @XmlElement(name = "elcGlcVarianceInclVat")
    BigDecimal elcGlcVarianceInclVat = BigDecimal.ZERO;
    @XmlElement(name = "elcItemCostInclVat")
    BigDecimal elcItemCostInclVat = BigDecimal.ZERO;


    @XmlElement(name = "exculdedCostlineAmountAtSpot")

    private BigDecimal exculdedCostlineAmountAtSpot = BigDecimal.ZERO;

    @XmlElement(name = "exculdedCostlineAmountAtForward")
    private BigDecimal exculdedCostlineAmountAtForward = BigDecimal.ZERO;


    @XmlElement(name = "bondedItemsCustomsTotals")
    BigDecimal bondedItemsCustomsTotals = BigDecimal.ZERO;

    public Map<CostApplicationBasis, BigDecimal> getCostApplicationBasisCost() {
        return costApplicationBasisCost;
    }

    public void setCostApplicationBasisCost(EnumMap<CostApplicationBasis, BigDecimal> costApplicationBasisCost) {
        this.costApplicationBasisCost = costApplicationBasisCost;
    }

    public Map<CostGroup, BigDecimal> getTotalImportCostExVatAtSpot() {
        return totalImportCostExVatAtSpot;
    }

    public void setTotalImportCostExVatAtSpot(EnumMap<CostGroup, BigDecimal> totalImportCostExVatAtSpot) {
        this.totalImportCostExVatAtSpot = totalImportCostExVatAtSpot;
    }

    public Map<CostGroup, BigDecimal> getTotalImportCostExVatAtForward() {
        return totalImportCostExVatAtForward;
    }

    public void setTotalImportCostExVatAtForward(EnumMap<CostGroup, BigDecimal> totalImportCostExVatAtForward) {
        this.totalImportCostExVatAtForward = totalImportCostExVatAtForward;
    }

    public Map<CostGroup, BigDecimal> getTotalExportCostExVatAtSpot() {
        return totalExportCostExVatAtSpot;
    }

    public void setTotalExportCostExVatAtSpot(EnumMap<CostGroup, BigDecimal> totalExportCostExVatAtSpot) {
        this.totalExportCostExVatAtSpot = totalExportCostExVatAtSpot;
    }

    public Map<CostGroup, BigDecimal> getTotalExportCostExVatAtForward() {
        return totalExportCostExVatAtForward;
    }

    public void setTotalExportCostExVatAtForward(EnumMap<CostGroup, BigDecimal> totalExportCostExVatAtForward) {
        this.totalExportCostExVatAtForward = totalExportCostExVatAtForward;
    }

    public BigDecimal getTotalVat() {
        return totalVat;
    }

    public void setTotalVat(BigDecimal totalVat) {
        this.totalVat = totalVat;
    }

    public BigDecimal getDutiableCostAtSpot() {
        return dutiableCostAtSpot;
    }

    public void setDutiableCostAtSpot(BigDecimal dutiableCostAtSpot) {
        this.dutiableCostAtSpot = dutiableCostAtSpot;
    }

    public BigDecimal getDutiableCost() {
        return dutiableCost;
    }

    public void setDutiableCost(BigDecimal dutiableCost) {
        this.dutiableCost = dutiableCost;
    }

    public BigDecimal getDutiableCostAtForward() {
        return dutiableCostAtForward;
    }

    public void setDutiableCostAtForward(BigDecimal dutiableCostAtForward) {
        this.dutiableCostAtForward = dutiableCostAtForward;
    }

    public BigDecimal getTotalRevenueInclVAT() {
        return totalRevenueInclVAT;
    }

    public void setTotalRevenueInclVAT(BigDecimal totalRevenueInclVAT) {
        this.totalRevenueInclVAT = totalRevenueInclVAT;
    }

    public BigDecimal getMarginInclVAT() {
        return marginInclVAT;
    }

    public void setMarginInclVAT(BigDecimal marginInclVAT) {
        this.marginInclVAT = marginInclVAT;
    }

    public BigDecimal getMarginPercentInclVAT() {
        return marginPercentInclVAT;
    }

    public void setMarginPercentInclVAT(BigDecimal marginPercentInclVAT) {
        this.marginPercentInclVAT = marginPercentInclVAT;
    }

    public BigDecimal getMarkupPercentInclVat() {
        return markupPercentInclVat;
    }

    public void setMarkupPercentInclVat(BigDecimal markupPercentInclVat) {
        this.markupPercentInclVat = markupPercentInclVat;
    }

    public BigDecimal getTotalRevenueExclVAT() {
        return totalRevenueExclVAT;
    }

    public void setTotalRevenueExclVAT(BigDecimal totalRevenueExclVAT) {
        this.totalRevenueExclVAT = totalRevenueExclVAT;
    }

    public BigDecimal getMarginExclVAT() {
        return marginExclVAT;
    }

    public void setMarginExclVAT(BigDecimal marginExclVAT) {
        this.marginExclVAT = marginExclVAT;
    }

    public BigDecimal getMarginPercentExclVAT() {
        return marginPercentExclVAT;
    }

    public void setMarginPercentExclVAT(BigDecimal marginPercentExclVAT) {
        this.marginPercentExclVAT = marginPercentExclVAT;
    }

    public BigDecimal getMarkupPercentExclVat() {
        return markupPercentExclVat;
    }

    public void setMarkupPercentExclVat(BigDecimal markupPercentExclVat) {
        this.markupPercentExclVat = markupPercentExclVat;
    }

    public BigDecimal getMarginExclVatInclCostToServe() {
        return marginExclVatInclCostToServe;
    }

    public void setMarginExclVatInclCostToServe(BigDecimal marginExclVatInclCostToServe) {
        this.marginExclVatInclCostToServe = marginExclVatInclCostToServe;
    }

    public BigDecimal getMarginExclVatCostToServe() {
        return marginExclVatCostToServe;
    }

    public void setMarginExclVatCostToServe(BigDecimal marginExclVatCostToServe) {
        this.marginExclVatCostToServe = marginExclVatCostToServe;
    }

    public BigDecimal lookupCostApplicationBasis(CostApplicationBasis costApplicationBasis) {
        return costApplicationBasisCost.get(costApplicationBasis);
    }

    public BigDecimal lookupTotalCostExVat(CostGroup costGroup, boolean spotRate) {
        BigDecimal importCost = lookupTotalCostExVat(costGroup, true, spotRate);
        BigDecimal exportCost = lookupTotalCostExVat(costGroup, false, spotRate);
        return importCost.add(exportCost);
    }

    public BigDecimal lookupTotalCostExVat(CostGroup costGroup, boolean importCost, boolean spotRate) {
        BigDecimal cost;
        if (spotRate) {
            if (importCost) {
                cost = totalImportCostExVatAtSpot.get(costGroup);
            } else {
                cost = totalExportCostExVatAtSpot.get(costGroup);
            }
        } else {
            if (importCost) {
                cost = totalImportCostExVatAtForward.get(costGroup);
            } else {
                cost = totalExportCostExVatAtForward.get(costGroup);
            }
        }
        return cost != null ? cost : BigDecimal.ZERO;
    }

    public BigDecimal lookupTotalVat() {
        return totalVat;
    }

    public BigDecimal lookupDutiable(boolean spotRate) {
        return spotRate ? dutiableCostAtSpot : dutiableCostAtForward;
    }

    public void addCostApplicationBasis(CostApplicationBasis costApplicationBasis, BigDecimal amount) {
        BigDecimal value = amount;
        if (costApplicationBasisCost.containsKey(costApplicationBasis)) {
            value = value.add(costApplicationBasisCost.get(costApplicationBasis));
        }
        costApplicationBasisCost.put(costApplicationBasis, value);
    }

    public void addVat(BigDecimal amount) {
        totalVat = totalVat.add(amount);
    }

    public void clearTotals() {
        //do not use map.clear as it is Slow!
        setCostApplicationBasisCost(new EnumMap<CostApplicationBasis, BigDecimal>(CostApplicationBasis.class));
        setTotalImportCostExVatAtSpot(new EnumMap<CostGroup, BigDecimal>(CostGroup.class));
        setTotalImportCostExVatAtForward(new EnumMap<CostGroup, BigDecimal>(CostGroup.class));
        setTotalExportCostExVatAtSpot(new EnumMap<CostGroup, BigDecimal>(CostGroup.class));
        setTotalExportCostExVatAtForward(new EnumMap<CostGroup, BigDecimal>(CostGroup.class));

        totalVat = BigDecimal.ZERO;
        dutiableCost = BigDecimal.ZERO;
        dutiableCostAtSpot = BigDecimal.ZERO;
        dutiableCostAtForward = BigDecimal.ZERO;
        marginExclVAT = BigDecimal.ZERO;
        marginInclVAT = BigDecimal.ZERO;
        marginPercentExclVAT = BigDecimal.ZERO;
        marginPercentInclVAT = BigDecimal.ZERO;
        totalRevenueExclVAT = BigDecimal.ZERO;
        totalRevenueInclVAT = BigDecimal.ZERO;
        markupPercentExclVat = BigDecimal.ZERO;
        markupPercentInclVat = BigDecimal.ZERO;
        marginExclVatCostToServe = BigDecimal.ZERO;
        marginExclVatInclCostToServe = BigDecimal.ZERO;

        exculdedCostlineAmountAtSpot = BigDecimal.ZERO;
        exculdedCostlineAmountAtForward = BigDecimal.ZERO;
        bondedItemsCustomsTotals = BigDecimal.ZERO;
    }

    public void addTotalCostExVat(CostLine costLine, BigDecimal amountInSpot, BigDecimal amountInForward) {
        CostGroup costGroup = costLine.getCostLineTemplate().getCostGroup();
        CostLinePayerType costLinePayerType = costLine.getCostLinePayerType();
        BigDecimal value = amountInSpot;
        if (CostLinePayerType.IMPORTER.equals(costLinePayerType)) {
            if (totalImportCostExVatAtSpot.containsKey(costGroup)) {
                value = value.add(totalImportCostExVatAtSpot.get(costGroup));
            }
            totalImportCostExVatAtSpot.put(costGroup, value);

            value = amountInForward;
            if (totalImportCostExVatAtForward.containsKey(costGroup)) {
                value = value.add(totalImportCostExVatAtForward.get(costGroup));
            }
            totalImportCostExVatAtForward.put(costGroup, value);
        } else if (CostLinePayerType.EXPORTER.equals(costLinePayerType)) {
            if (totalExportCostExVatAtSpot.containsKey(costGroup)) {
                value = value.add(totalExportCostExVatAtSpot.get(costGroup));
            }
            totalExportCostExVatAtSpot.put(costGroup, value);

            value = amountInForward;
            if (totalExportCostExVatAtForward.containsKey(costGroup)) {
                value = value.add(totalExportCostExVatAtForward.get(costGroup));
            }
            totalExportCostExVatAtForward.put(costGroup, value);
        }
    }

    public void addTotalExcludedCost(CostLine costLine, BigDecimal amountInSpot, BigDecimal amountInForward) {
        if (costLine.isExcludeFromUnitPerCost()) {
            exculdedCostlineAmountAtSpot = exculdedCostlineAmountAtSpot.add(amountInSpot);
            exculdedCostlineAmountAtForward = exculdedCostlineAmountAtForward.add(amountInForward);
        }
    }

    public void addDutiableCost(CostLine costLine, Costed costed, BigDecimal cost, RateOfExchanges rateOfExchanges, boolean totalUnitPrice,
                                BigDecimal foreignToForeignRate) {

        BigDecimal costInSpot = cost.multiply(rateOfExchanges.getSpotRate());
        BigDecimal costInForward = cost.multiply(rateOfExchanges.getForwardRate());
        String costLineCode = costLine.getCostLineTemplate().getCode();
        CostingCell costingCell = costed.getCostLineCosting().getCostingCell(costLineCode);
        boolean dutiable = costingCell != null ? costingCell.isDutiable() : costLine.isDutiable();

        if (costLineCode.equals(CostLineNames.SUPPLY_SUPPLY)) {
            addDutiableCost(costed, cost, costInSpot, costInForward, foreignToForeignRate);
        } else if (totalUnitPrice) {
            boolean exporter = CostLinePayerType.EXPORTER.equals(costLine.getCostLinePayerType());
            if (!dutiable && exporter) {
                if (costLine.getCostLineTemplate().isDiscount()) {
                    //exworks is negative so we add it
                    addDutiableCost(costed, cost, costInSpot, costInForward, foreignToForeignRate);
                } else {
                    subtractDutiableCost(costed, cost, costInSpot, costInForward, foreignToForeignRate);
                }
            }
        } else {
            if (dutiable) {
                addDutiableCost(costed, cost, costInSpot, costInForward, foreignToForeignRate);
            }
        }
    }

    public void addDutiableInSpot(BigDecimal amount) {
        dutiableCostAtSpot = dutiableCostAtSpot.add(amount);
        if (lessThanZero(dutiableCostAtSpot)) {
            dutiableCostAtSpot = BigDecimal.ZERO;
        }
    }

    public void addDutiableInForward(BigDecimal amount) {
        dutiableCostAtForward = dutiableCostAtForward.add(amount);
        if (lessThanZero(dutiableCostAtForward)) {
            dutiableCostAtForward = BigDecimal.ZERO;
        }
    }

    public void addDutiableNoRate(BigDecimal amount) {
        setDutiableCost(getDutiableCost().add(amount));
        if (lessThanZero(dutiableCost)) {
            setDutiableCost(BigDecimal.ZERO);
        }
    }

    private boolean lessThanZero(BigDecimal value) {
        return value.compareTo(BigDecimal.ZERO) == -1;
    }

    private void subtractDutiableCost(Costed costed, BigDecimal cost, BigDecimal costInSpot, BigDecimal costInForward,
                                      BigDecimal foreignToForeignRate) {
        addDutiableCost(costed, cost.negate(), costInSpot, costInForward, foreignToForeignRate);
    }

    private void addDutiableCost(Costed costed, BigDecimal cost, BigDecimal costInSpot, BigDecimal costInForward, BigDecimal foreignToForeignRate) {
        if (costed != null) {
            CostedTotals costedTotals = costed.getCostedTotals();
            costedTotals.addDutiableInSpot(costInSpot);
            costedTotals.addDutiableInForward(costInForward);
            costedTotals.addDutiableNoRate(cost.multiply(foreignToForeignRate));
            addDutiableCost(costed.getParent(), cost, costInSpot, costInForward, foreignToForeignRate);
        }
    }

    private boolean isDiscountCost(CostLine costLine) {
        return costLine.getCostLineTemplate().isDiscount();
    }

    private void addSupplyCost(Costed costed, BigDecimal cost, RateOfExchanges rateOfExchanges) {
        if (costed != null) {
            CostedTotals costedTotals = costed.getCostedTotals();
            costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLY_COST, cost);
            costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLY_COST_SPOT_RATE, cost.multiply(rateOfExchanges.getSpotRate()));
            costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLY_COST_FWD_RATE, cost.multiply(rateOfExchanges.getForwardRate()));
            addSupplyCost(costed.getParent(), cost, rateOfExchanges);
        }
    }

    private void addSampleAndSpareSupplyCost(Costed costed, BigDecimal cost, RateOfExchanges rateOfExchanges) {
        if (costed != null) {
            CostedTotals costedTotals = costed.getCostedTotals();
            costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLY_COST_SAMPLES_AND_SPARES, cost);
            costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLY_COST_SPOT_RATE_SAMPLES_AND_SPARES,
                    cost.multiply(rateOfExchanges.getSpotRate()));
            costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLY_COST_FWD_RATE_SAMPLES_AND_SPARES,
                    cost.multiply(rateOfExchanges.getForwardRate()));
            addSampleAndSpareSupplyCost(costed.getParent(), cost, rateOfExchanges);
        }
    }

    private void addSupplyCostIncDiscount(Costed costed, BigDecimal cost, RateOfExchanges rateOfExchanges) {
        if (costed != null) {
            CostedTotals costedTotals = costed.getCostedTotals();
            costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLY_COST_INC_DISCOUNT, cost);
            costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLY_COST_INC_DISCOUNT_SPT_RATE,
                    cost.multiply(rateOfExchanges.getSpotRate()));
            costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLY_COST_INC_DISCOUNT_FWD_RATE,
                    cost.multiply(rateOfExchanges.getForwardRate()));
            addSupplyCostIncDiscount(costed.getParent(), cost, rateOfExchanges);
        }
    }

    private void addSupplierInvoice(Costed costed, BigDecimal cost, RateOfExchanges rateOfExchanges, RateOfExchanges rateFeed) {
        if (costed != null) {
            CostedTotals costedTotals = costed.getCostedTotals();
            addSupplierInvoiceCurrentCosting(cost, rateOfExchanges, costedTotals, rateFeed);
            addSupplierInvoice(costed.getParent(), cost, rateOfExchanges, rateFeed);
        }
    }

    public void addSupplierInvoiceCurrentCosting(BigDecimal cost, RateOfExchanges rateOfExchanges, CostedTotals costedTotals,
                                                 RateOfExchanges rateFeed) {
        costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLIER_INVOICE, cost);
        costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLIER_INVOICE_SPT_RATE, cost.multiply(rateOfExchanges.getSpotRate()));
        costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLIER_INVOICE_FWD_RATE, cost.multiply(rateOfExchanges.getForwardRate()));
        if (rateFeed != null && rateFeed.getSpotRate() != null && rateFeed.getForwardRate() != null) {
            costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLIER_INVOICE_RATE_FEED_SPT_RATE, cost.multiply(rateFeed.getSpotRate()));
            costedTotals.addCostApplicationBasis(CostApplicationBasis.SUPPLIER_INVOICE_RATE_FEED_FWD_RATE, cost.multiply(rateFeed.getForwardRate()));
        }
    }

    public void addAdditionalSupplyCosts(CostLine costLineSummary, Costed costed, BigDecimal cost, RateOfExchanges rateOfExchanges,
                                         boolean totalUnitPrice, RateOfExchanges rateFeed) {
        if (costed != null && !CostLineNames.SUPPLY_SUPPLY.equals(costLineSummary.getCostLineTemplate().getCode())) {
            if (includeCostLineCost(costLineSummary, totalUnitPrice)) {
                if (isDiscountCost(costLineSummary)) {
                    addSupplyCostIncDiscount(costed, cost, rateOfExchanges);
                }
                addSupplierInvoice(costed, cost, rateOfExchanges, rateFeed);
            }
        }
    }

    public void addSupplyCostBasis(CostLine costLine, Costed costed, BigDecimal cost, RateOfExchanges rateOfExchanges,
                                   boolean sampleOrSpareItem, RateOfExchanges rateFeed) {
        if (costed != null && CostLineNames.SUPPLY_SUPPLY.equals(costLine.getCostLineTemplate().getCode())) {

            if (cost == null) {
                cost = BigDecimal.ZERO;
            }
            BigDecimal sampleOrSpareCost = BigDecimal.ZERO;
            if (sampleOrSpareItem) {
                sampleOrSpareCost = cost;
                cost = BigDecimal.ZERO;
            }
            addSampleAndSpareSupplyCost(costed, sampleOrSpareCost, rateOfExchanges);
            addSupplyCost(costed, cost, rateOfExchanges);
            addSupplyCostIncDiscount(costed, cost, rateOfExchanges);
            addSupplierInvoice(costed, cost, rateOfExchanges, rateFeed);
        }
    }

    private boolean includeCostLineCost(CostLine costLine, boolean totalUnitPrice) {
        if (CostLinePayerType.EXPORTER.equals(costLine.getCostLinePayerType())) {
            if (totalUnitPrice) {
                if (!costLine.isExcludeFromCostTotal()) {
                    if (!CostLineNames.SUPPLY_SUPPLY.equals(costLine.getCostLineTemplate().getCode())) {
                        return false;
                    }
                }
            }
            return true;
        }
        return false;
    }

    public BigDecimal getTotalCost(boolean spotRate, CostingContextType contextType) {
        switch (contextType) {
            case IMPORT:
                return getTotalForRate(spotRate, totalImportCostExVatAtSpot, totalImportCostExVatAtForward);
            case EXPORT:
                return getTotalForRate(spotRate, totalExportCostExVatAtSpot, totalExportCostExVatAtForward);
            default:
                return BigDecimal.ZERO;
        }

    }

    private BigDecimal getTotalForRate(boolean spotRate, Map<CostGroup, BigDecimal> totalImportCostExVatAtSpot,
                                       Map<CostGroup, BigDecimal> totalImportCostExVatAtForward) {
        if (spotRate) {
            return sumMapValues(totalImportCostExVatAtSpot);
        } else {
            return sumMapValues(totalImportCostExVatAtForward);
        }
    }

    private BigDecimal sumMapValues(Map<CostGroup, BigDecimal> costGroupBigDecimalMap) {
        BigDecimal total = BigDecimal.ZERO;
        Collection<BigDecimal> values = costGroupBigDecimalMap.values();
        for (BigDecimal value : values) {
            total = total.add(value);
        }
        return total;
    }

    public BigDecimal getElcUnitCostExcVat() {
        return elcUnitCostExcVat;
    }

    public void setElcUnitCostExcVat(BigDecimal elcUnitCostExcVat) {
        this.elcUnitCostExcVat = elcUnitCostExcVat;
    }

    public BigDecimal getElcGlcItemVarianceExcVat() {
        return elcGlcItemVarianceExcVat;
    }

    public void setElcGlcItemVarianceExcVat(BigDecimal elcGlcItemVarianceExcVat) {
        this.elcGlcItemVarianceExcVat = elcGlcItemVarianceExcVat;
    }

    public BigDecimal getElcGlcVarianceExcVat() {
        return elcGlcVarianceExcVat;
    }

    public void setElcGlcVarianceExcVat(BigDecimal elcGlcVarianceExcVat) {
        this.elcGlcVarianceExcVat = elcGlcVarianceExcVat;
    }

    public BigDecimal getElcItemCostExcVat() {
        return elcItemCostExcVat;
    }

    public void setElcItemCostExcVat(BigDecimal elcItemCostExcVat) {
        this.elcItemCostExcVat = elcItemCostExcVat;
    }

    public BigDecimal getElcUnitCostInclVat() {
        return elcUnitCostInclVat;
    }

    public void setElcUnitCostInclVat(BigDecimal elcUnitCostInclVat) {
        this.elcUnitCostInclVat = elcUnitCostInclVat;
    }

    public BigDecimal getElcGlcItemVarianceInclVat() {
        return elcGlcItemVarianceInclVat;
    }

    public void setElcGlcItemVarianceInclVat(BigDecimal elcGlcItemVarianceInclVat) {
        this.elcGlcItemVarianceInclVat = elcGlcItemVarianceInclVat;
    }

    public BigDecimal getElcGlcVarianceInclVat() {
        return elcGlcVarianceInclVat;
    }

    public void setElcGlcVarianceInclVat(BigDecimal elcGlcVarianceInclVat) {
        this.elcGlcVarianceInclVat = elcGlcVarianceInclVat;
    }

    public BigDecimal getElcItemCostInclVat() {
        return elcItemCostInclVat;
    }

    public void setElcItemCostInclVat(BigDecimal elcItemCostInclVat) {
        this.elcItemCostInclVat = elcItemCostInclVat;
    }

    public BigDecimal getExculdedCostlineAmountAtSpot() {
        return exculdedCostlineAmountAtSpot;
    }

    public BigDecimal getExculdedCostlineAmountAtForward() {
        return exculdedCostlineAmountAtForward;
    }

    public void clearELCCosting() {
        setElcUnitCostInclVat(BigDecimal.ZERO);
        setElcUnitCostExcVat(BigDecimal.ZERO);
        clearElcRevenueExcludeBase();

    }

    public void clearElcRevenueExcludeBase() {
        setElcGlcItemVarianceInclVat(BigDecimal.ZERO);
        setElcGlcVarianceInclVat(BigDecimal.ZERO);
        setElcGlcVarianceExcVat(BigDecimal.ZERO);
        setElcItemCostInclVat(BigDecimal.ZERO);
        setElcItemCostExcVat(BigDecimal.ZERO);
        setElcGlcItemVarianceExcVat(BigDecimal.ZERO);
    }

    public void addBondedTotalAmount(BigDecimal bigDecimal) {
        this.bondedItemsCustomsTotals = ObjectUtils.firstNonNull(this.bondedItemsCustomsTotals, BigDecimal.ZERO).add(bigDecimal);
    }

    public BigDecimal getBondedItemsCustomsTotals() {
        return bondedItemsCustomsTotals;
    }
}