AbstractIncotermBasedDocumentLineItem.java

package com.tradecloud.domain.item;

import com.tradecloud.domain.common.Incoterm;

import javax.persistence.MappedSuperclass;
import java.math.BigDecimal;
import java.util.*;

/**
 * TODO - not yet imported from BB.
 */
@MappedSuperclass
public abstract class AbstractIncotermBasedDocumentLineItem extends DocumentLineItem implements IncotermBasedLineItem {

    public AbstractIncotermBasedDocumentLineItem() {
        super();
    }

    public BigDecimal getAmountRatio(boolean atCostNotSale) {
        BigDecimal amount = getAmountAtPriceIncoterm(atCostNotSale);
        if (amount == null)
            return null;
        IncotermBasedDocument document = getDocument();
        BigDecimal documentAmount = document.getAbsoluteAmountAtPriceIncoterm(atCostNotSale);
        if (documentAmount == null)
            return null;
        return amount.divide(documentAmount);
    }

    public BigDecimal getAmountAtIncoterm(boolean atCostNotSale) {
        return getAmount(atCostNotSale, getIncoterm(atCostNotSale));
    }

    public Map getAmountsByIncoterm(boolean atCostNotSale) {
        return atCostNotSale ? getCostAmountsByIncoterm() : getSaleAmountsByIncoterm();
    }

    protected Map getCostAmountsByIncoterm() {
        IncotermBasedDocument document = getDocument();
        Map documentCostAmountsByIncoterm = document.getAmountsByIncoterm(true);
        int n = documentCostAmountsByIncoterm.size();
        Map costAmountsByIncoterm = new HashMap();

        // For precision purposes rather add price incoterm entry with item's
        // amount at price incoterm
        Incoterm costPriceIncoterm = document.getPriceIncoterm(true);
        BigDecimal costAmountAtPriceIncoterm = getAmountAtPriceIncoterm(true);
        costAmountsByIncoterm.put(costPriceIncoterm, costAmountAtPriceIncoterm);

        BigDecimal amountRatio = getAmountRatio(true);
        for (Iterator iter = documentCostAmountsByIncoterm.keySet().iterator(); iter.hasNext(); ) {
            Incoterm incoterm = (Incoterm) iter.next();
            if (incoterm == costPriceIncoterm)
                continue;
            BigDecimal orderCostAmount = (BigDecimal) documentCostAmountsByIncoterm.get(incoterm);
            costAmountsByIncoterm.put(incoterm, orderCostAmount.multiply(amountRatio));
        }
        return costAmountsByIncoterm;
    }

    protected Map getSaleAmountsByIncoterm() {
        IncotermBasedDocument document = getDocument();
        Incoterm salePriceIncoterm = document.getPriceIncoterm(false);
        Incoterm saleIncoterm = document.getIncoterm(false);

        Map saleAmountsByIncoterm = new HashMap(5);
        BigDecimal saleAmountAtPriceIncoterm = getAmountAtPriceIncoterm(false);
        saleAmountsByIncoterm.put(salePriceIncoterm, saleAmountAtPriceIncoterm);
        if (saleIncoterm != salePriceIncoterm) {
            // We don't have the amount for sale incoterm yet, so just
            // set it to amount for sale price incoterm initially
            saleAmountsByIncoterm.put(saleIncoterm, saleAmountAtPriceIncoterm);
        }
        return saleAmountsByIncoterm;
    }

    public BigDecimal getAmount(boolean atCostNotSale, Incoterm targetIncoterm) {
        Map amountsByIncoterm = getAmountsByIncoterm(atCostNotSale);

        // First look for an exact match
        BigDecimal amount = (BigDecimal) amountsByIncoterm.get(targetIncoterm);
        if (amount != null || targetIncoterm == null)
            return amount;

        // Next look for closest match available
        List incoterms = new ArrayList(amountsByIncoterm.keySet());
        Incoterm closestIncoterm = Incoterm.findClosestIncoterm(targetIncoterm, incoterms, false, true);
        return (BigDecimal) amountsByIncoterm.get(closestIncoterm);
    }

    public Incoterm getIncoterm(boolean atCostNotSale) {
        return getDocument().getIncoterm(atCostNotSale);
    }

    public Incoterm getPriceIncoterm(boolean atCostNotSale) {
        return getDocument().getPriceIncoterm(atCostNotSale);
    }

    public boolean isImport() {
        return getDocument().isImport();
    }

    public abstract BigDecimal getUnitPrice(boolean atCostNotSale);

    public abstract BigDecimal getUnitQuantity(boolean atCostNotSale);

    /**
     * @see com.rmbgs.ts.domain.doc.IncotermBasedLineItem#getPricesByIncoterm(boolean)
     */
    public Map getPricesByIncoterm(boolean atCostNotSale) {
        return atCostNotSale ? getCostPricesByIncoterm() : getSalePricesByIncoterm();
    }

    private Map getCostPricesByIncoterm() {
        Map costAmountsByIncoterm = getAmountsByIncoterm(true);
        int n = costAmountsByIncoterm.size();
        Map costPricesByIncoterm = new HashMap();
        IncotermBasedDocument document = getDocument();

        // For precision purposes rather add price incoterm entry with item's
        // price
        Incoterm costPriceIncoterm = document.getPriceIncoterm(true);
        BigDecimal costPrice = getUnitPrice(true);

        costPricesByIncoterm.put(costPriceIncoterm, costPrice);

        BigDecimal unitQuantity = getUnitQuantity(true);
        for (Iterator iter = costAmountsByIncoterm.keySet().iterator(); iter.hasNext(); ) {
            Incoterm incoterm = (Incoterm) iter.next();
            if (incoterm == costPriceIncoterm)
                continue;
            BigDecimal costAmount = (BigDecimal) costAmountsByIncoterm.get(incoterm);
            costPricesByIncoterm.put(incoterm, costAmount.divide(unitQuantity));
        }
        return costPricesByIncoterm;
    }

    private Map getSalePricesByIncoterm() {
        IncotermBasedDocument document = getDocument();
        Incoterm salePriceIncoterm = document.getPriceIncoterm(false);
        Incoterm saleIncoterm = document.getIncoterm(false);

        Map salePricesByIncoterm = new HashMap(5);
        BigDecimal unitPrice = getUnitPrice(false);
        salePricesByIncoterm.put(salePriceIncoterm, unitPrice);
        if (saleIncoterm != salePriceIncoterm) {
            // We don't have the price for sale incoterm yet, so just
            // set it to price for sale price incoterm initially
            salePricesByIncoterm.put(saleIncoterm, unitPrice);
        }
        return salePricesByIncoterm;
    }

}