PlannedSettlementHelper.java

package com.tradecloud.domain.document.invoice;

import com.tradecloud.domain.base.utils.MathUtils;
import com.tradecloud.domain.model.ordermanagement.SettlementSignoffState;
import com.tradecloud.domain.settlement.PlannedSettlement;
import com.tradecloud.domain.settlement.PlannedSettlementOrder;

import java.math.BigDecimal;
import java.util.*;

/**
 * Helper/Wrapper for the planned settlements Set to provider useful methods.
 *
 * @author ronan
 */
public class PlannedSettlementHelper {

    private static final BigDecimal ZERO = new BigDecimal("0.00");
    protected SettlementSignoffState signoffState;
    protected boolean outOfSync;
    protected Date signoffDate;
    protected Date unsignoffDate;
    protected Date rateRefreshDate;
    protected Set<PlannedSettlement> plannedSettlements;
    private final BigDecimal ONE_HUNDRED = new BigDecimal("100.00");

    public PlannedSettlementHelper() {
    }

    public PlannedSettlementHelper(Set<PlannedSettlement> plannedSettlements) {
        this.outOfSync = false;
        this.signoffState = SettlementSignoffState.NEW;
        this.plannedSettlements = plannedSettlements;
    }

    /**
     * Gets the total value of all the planned settlements.
     *
     * @return
     */
    public BigDecimal getTotalValue() {
        if (plannedSettlements == null) {
            return ZERO;
        }
        BigDecimal total = BigDecimal.ZERO;

        for (PlannedSettlement plannedSettlement : plannedSettlements) {
            total = total.add(plannedSettlement.getAmount());
        }
        return total;
    }

    /**
     * Gets the total value of all the planned settlements (which uses the forward rate).
     *
     * @return
     */
    public BigDecimal getCostingCurrencyTotalValue() {
        if (plannedSettlements == null) {
            return ZERO;
        }
        BigDecimal total = new BigDecimal("0.00");

        for (PlannedSettlement plannedSettlement : plannedSettlements) {
            if (plannedSettlement.getAmountInCostingCurrency() != null) {
                total = total.add(plannedSettlement.getAmountInCostingCurrency());
            }
        }
        return total;
    }

    public BigDecimal getOrderCostingCurrencyTotalValue() {
        if (plannedSettlements == null) {
            return ZERO;
        }
        BigDecimal total = new BigDecimal("0.00");

        for (PlannedSettlement plannedSettlement : plannedSettlements) {
            Set<PlannedSettlementOrder> plannedSettlementOrders = plannedSettlement.getPlannedSettlementOrders();
            for (PlannedSettlementOrder plannedSettlementOrder : plannedSettlementOrders) {

                if (plannedSettlementOrder.getAmountInCostingCurrency() != null) {
                    total = total.add(plannedSettlementOrder.getAmountInCostingCurrency());
                }
            }
        }
        return total;
    }

    /**
     * Gets the total value of all the planned settlements using the spot rate .
     *
     * @return
     */
    public BigDecimal getCostingCurrencyTotalValueUsingSpotRate() {
        if (plannedSettlements == null) {
            return ZERO;
        }
        BigDecimal total = new BigDecimal("0.00");

        for (PlannedSettlement plannedSettlement : plannedSettlements) {
            if (plannedSettlement.getAmountInCostingCurrency() != null) {
                total = total.add(plannedSettlement.getAmountInCostingCurrencyUsingSpotRate());
            }
        }
        return total;
    }

    public BigDecimal getOrderCostingCurrencyTotalValueUsingSpotRate() {
        if (plannedSettlements == null) {
            return ZERO;
        }
        BigDecimal total = new BigDecimal("0.00");

        for (PlannedSettlement plannedSettlement : plannedSettlements) {
            Set<PlannedSettlementOrder> plannedSettlementOrders = plannedSettlement.getPlannedSettlementOrders();
            for (PlannedSettlementOrder plannedSettlementOrder : plannedSettlementOrders) {
                if (plannedSettlementOrder.getAmountInCostingCurrency() != null) {
//                    total = total.add(plannedSettlementOrder.getAmount().multiply(plannedSettlementOrder.getSpotRate()));
                    total = total.add(MathUtils.multiply(plannedSettlementOrder.getAmount(), plannedSettlementOrder.getSpotRate()));
                }
            }
        }
        return total;
    }

    // Use the shorter name
    public BigDecimal getWeightedAverageForwardRateOfExchange() {
        return MathUtils.safeDivide(getCostingCurrencyTotalValue(), getTotalValue());
    }

    /**
     * Weighted Average Rate of exchange.
     * The weighted average of all the planned settlement's forward rate of exchange
     * Calculated as: Sum of value in costing currency / sum of supply value
     *
     * @return
     */
    public BigDecimal getWeightAverageForwardRate() {
        return MathUtils.safeDivide(getCostingCurrencyTotalValue(), getTotalValue());
    }

    /**
     * Weighted Average Rate of exchange.
     * The weighted average of all the planned settlement's forward rate of exchange
     * Calculated as: Sum of value in costing currency / sum of supply value
     *
     * @return
     */
    public BigDecimal getWeightedAverageSpotRate() {
        return MathUtils.safeDivide(getCostingCurrencyTotalValueUsingSpotRate(), getTotalValue());
    }

    // Use the shorter name
    public BigDecimal getWeightedAverageSpotRateOfExchange() {
        return MathUtils.safeDivide(getCostingCurrencyTotalValueUsingSpotRate(), getTotalValue());
    }

    public boolean hasActiveSettlements() {
        if (plannedSettlements == null) {
            return false;
        }

        for (PlannedSettlement plannedSettlement : plannedSettlements) {
            if (plannedSettlement.getActive()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Do any of the settlements have treasury implications.
     *
     * @return
     */
    public boolean hasTreasuryImplication() {
        if (plannedSettlements == null) {
            return false;
        }
        for (PlannedSettlement plannedSettlement : plannedSettlements) {
            if (plannedSettlement.hasTreasuryImplication()) {
                return true;
            }
        }
        return false;
    }

    public int numActiveSettlements() {
        if (plannedSettlements == null) {
            return 0;
        }
        int num = 0;
        for (PlannedSettlement plannedSettlement : plannedSettlements) {
            if (plannedSettlement.getActive()) {
                num++;
            }
        }
        return num;
    }

    public boolean isOutOfSync() {
        return outOfSync;
    }

    public void setOutOfSync(boolean outOfSync) {
        this.outOfSync = outOfSync;
    }

    public Set<PlannedSettlement> getPlannedSettlements() {
        return plannedSettlements;
    }

    public void setPlannedSettlements(Set<PlannedSettlement> plannedSettlements) {
        this.plannedSettlements = plannedSettlements;
    }

    public Date getRateRefreshDate() {
        return rateRefreshDate;
    }

    public void setRateRefreshDate(Date rateRefreshDate) {
        this.rateRefreshDate = rateRefreshDate;
    }

    public Date getSignoffDate() {
        return signoffDate;
    }

    public void setSignoffDate(Date signoffDate) {
        this.signoffDate = signoffDate;
    }

    public SettlementSignoffState getSignoffState() {
        return signoffState;
    }

    public void setSignoffState(SettlementSignoffState signOffState) {
        this.signoffState = signOffState;
    }

    public Date getUnsignoffDate() {
        return unsignoffDate;
    }

    public void setUnsignoffDate(Date unsignoffDate) {
        this.unsignoffDate = unsignoffDate;
    }

    public void unsignoff(String client) {
        if (getSignoffState() == SettlementSignoffState.SIGNED_OFF) {
            setSignoffState(SettlementSignoffState.UNSIGNED_OFF);
            setUnsignoffDate(new Date());
            // notify treasury
            notifyTreasuryOfUnsignoff(client);
        }
    }

    /**
     * TODO - we don't call services from the domain tier in Tradecloud This
     * method will need to be refactored up to the service tier.
     */
    private void notifyTreasuryOfUnsignoff(String client) {
        // Collection settlementSet = getPlannedSettlements();
        // List requests = new ArrayList(settlementSet.size());
        // PlannedSettlementService pss =
        // PlannedSettlementService.getInstance();
        // Long clientID = client.getId();
        // Long treasuryID = client.getTreasuryID();
        // for (Iterator iter = settlementSet.iterator();
        // plannedSettlement.hasNext();) {
        // PlannedSettlement ps = (PlannedSettlement) plannedSettlement.next();
        // if (ps.getActive() && ps.isFormerlyExposed() &&
        // ps.canChangeForTreasury()) {
        // UnsignOffNotification request = new UnsignOffNotification();
        // request.setAllocation(pss.getSettlementCostType(ps.isRevenue()).getName());
        // request.setClientID(clientID);
        // request.setSettlementIdentifier(ps.getNumber());
        // request.setTreasuryID(treasuryID);
        // requests.add(request);
        // }
        // }
        // if (!requests.isEmpty()) { // have warnings to send
        // TreasuryIntegrationService.getInstance().notifyOfUnsignOff(requests);
        // }
    }

    public boolean isEmpty() {
        return plannedSettlements == null || plannedSettlements.isEmpty();
    }

    public boolean areAllDatesInSynch() {
        for (PlannedSettlement ps : plannedSettlements) {
            if (ps.isSettlementDateOutOfSynch()) {
                return false;
            }
        }
        return true;
    }

    public String getDateSynchMessage() {
        Set<String> messages = new HashSet<>();
        for (PlannedSettlement ps : plannedSettlements) {
            if (ps.isSettlementDateOutOfSynch()) {
                messages.add(addDateSynchMessage(ps));
            }
        }

        StringBuilder builder = new StringBuilder();
        for (String string : messages) {
            builder.append(string);
        }
        return builder.toString();
    }

    private String addDateSynchMessage(PlannedSettlement ps) {
        StringBuilder builder = new StringBuilder();
        builder.append("Date ").append(ps.getFormattedSettlementDate()).append(" should be ")
                .append(ps.getPlannedSettlementMemento().getFormattedSettlementDate()).append(".");
        return builder.toString();
    }

    public BigDecimal getPercentage(PlannedSettlement ps) {
        if (getTotalValue().compareTo(ZERO) > 0) {
            return MathUtils.setDisplayScale(MathUtils.multiply(MathUtils.divide(ps.getAmount(), getTotalValue()), ONE_HUNDRED));
        }
        return ZERO;
    }

    public Date getSettlementDate() {
        if (isEmpty()) {
            return null;
        } else {
            return plannedSettlements.iterator().next().getSettlementDate();
        }

    }

    public BigDecimal getTotalValueDisplay() {
        int scale = MathUtils.SCALE_FOUR;

        return MathUtils.setScale(getTotalValue(), scale);
    }

    public BigDecimal getWeightedAverageSpotRateOfExchangeDisplay() {
        int scale = MathUtils.SCALE_FOUR;

        return MathUtils.setScale(getWeightedAverageSpotRateOfExchange(), scale);
    }

    public BigDecimal getWeightedAverageForwardRateOfExchangeDisplay() {
        int scale = MathUtils.SCALE_FOUR;

        return MathUtils.setScale(getWeightedAverageForwardRateOfExchange(), scale);
    }

    public PlannedSettlementOrder findMatching(String reference) {
        for (PlannedSettlement plannedSettlement : plannedSettlements) {
            PlannedSettlementOrder order = findMatchingPlannedSettlementOrder(reference, plannedSettlement);
            if (order != null) {
                return order;
            }
        }
        return null;
    }

    public static PlannedSettlementOrder findMatchingPlannedSettlementOrder(String reference, PlannedSettlement plannedSettlement) {
        Set<PlannedSettlementOrder> plannedSettlementOrders = plannedSettlement.getPlannedSettlementOrders();
        for (PlannedSettlementOrder plannedSettlementOrder : plannedSettlementOrders) {
            if (plannedSettlementOrder.getReference().equals(reference)) {
                return plannedSettlementOrder;
            }
        }
        return null;
    }

    public static PlannedSettlement findMatchingPlannedSettlement(String orderReference, Set<PlannedSettlement> plannedSettlements) {
        for (PlannedSettlement plannedSettlement : plannedSettlements) {
            PlannedSettlementOrder matchingPlannedSettlementOrder = findMatchingPlannedSettlementOrder(orderReference, plannedSettlement);
            if (matchingPlannedSettlementOrder != null) {
                return plannedSettlement;
            }
        }
        return null;
    }

    public List<PlannedSettlementOrder> findMatchingOrders(String reference) {
        List<PlannedSettlementOrder> plannedSettlementOrders = new ArrayList<>();
        for (PlannedSettlement plannedSettlement : plannedSettlements) {
            PlannedSettlementOrder order = findMatchingPlannedSettlementOrder(reference, plannedSettlement);
            if (order != null) {
                plannedSettlementOrders.add(order);
            }
        }
        return plannedSettlementOrders;
    }
}