LetterOfCreditUtils.java

package com.tradecloud.domain.letterofcredit;

import com.tradecloud.domain.base.utils.DateUtils;
import com.tradecloud.domain.base.utils.MathUtils;
import com.tradecloud.domain.common.Currency;
import com.tradecloud.domain.item.LineItem;
import com.tradecloud.domain.model.Money;
import com.tradecloud.domain.model.ordermanagement.OrderState;
import com.tradecloud.domain.model.ordermanagement.PurchaseOrder;
import com.tradecloud.domain.model.payment.PaymentMethod;
import com.tradecloud.domain.model.payment.PaymentTerm;
import org.apache.commons.lang.StringUtils;

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

/**
 * Putting some of the logic from the modules LetterOfCredit class here. We have more of an aenemic data model.
 */
public class LetterOfCreditUtils {

    // TODO. Surely there is a better way than these consts?

    public static final String LC_USANCE_CODE = "LC_USANCE";

    public static final String LC_SIGHT_CODE = "LC_SIGHT";

    public static final Collection<String> LC_ELIGIBLE_ORDER_PAYMENT_METHOD_CODES = Arrays.asList(LC_USANCE_CODE, LC_SIGHT_CODE);

    public static final Collection<String> LC_SIGHT_PAYMENT_TERM_CODES = Arrays.asList("SIGHT_15_DAYS", "SIGHT_30_DAYS");

    public static final Collection<String> LC_USANCE_PAYMENT_TERM_CODES = Arrays.asList("DAYS_30", "DAYS_45", "DAYS_60",
            "DAYS_90", "DAYS_120", "DAYS_150", "DAYS_180", "DAYS_360", "DAYS_50", "DAYS_99", "DAYS_888", "DAYS_990", "DAYS_998", "DAYS_999",
            "DAYS_40", "DAYS_210", "USANCE_60_DAYS", "USANCE_90_DAYS", "USANCE_120_DAYS");

    public static final OrderState LC_ELIGIBLE_ORDER_STATES[] = new OrderState[]{OrderState.SIGNED_OFF, OrderState.AWAITING_LSP_SIGNOFF,
            OrderState.BOOKED_IN, OrderState.FREIGHT_RECEIVED};

    private static final String DELIMITER_COMMA = ",";

    // This could probably be somewhere common, or even a query
    public static Money calculateAmount(Collection<PurchaseOrder> purchaseOrders) {
        Currency currency = null;
        BigDecimal amount = BigDecimal.ZERO;
        for (PurchaseOrder purchaseOrder : purchaseOrders) {
            if (currency == null) {
                currency = purchaseOrder.getCurrency();
            }
            amount = amount.add(purchaseOrder.getTotalInvoiceValue());
        }
        return new Money(MathUtils.setScale(amount, 2), currency);
    }

    public static String generateShippingMarks(Collection<PurchaseOrder> purchaseOrders, ShippingMarksDescription shippingMarksDescription) {
        List<String> references = new ArrayList<String>();
        for (PurchaseOrder purchaseOrder : purchaseOrders) {
            switch (shippingMarksDescription) {
                case ORDER_REFERENCE:
                    references.add(purchaseOrder.getOrderReference());
                    break;
                case SHIPPING_REFERENCE:
                    references.add(purchaseOrder.getShippingInformation().getShippingReference());
                    break;
            }
        }
        return StringUtils.join(references, DELIMITER_COMMA);
    }

    public static String generateShippingMarks(LetterOfCredit lc, ShippingMarksDescription shippingMarksDescription) {
        return generateShippingMarks(lc.getPurchaseOrders(), shippingMarksDescription);
    }

    // Use the service method call so the line item descriptions can be queried
    @Deprecated
    public static String generateGoodsDescription(Collection<PurchaseOrder> purchaseOrders, LetterOfCreditGoodsDescription goodsDescription) {
        switch (goodsDescription) {
            case ITEM_DESCRIPTIONS:
                return generateGoodsDescriptionFromPurchaseOrderItems(purchaseOrders);
            case ORDER_RECIPIENT:
                return purchaseOrders.iterator().next().getOrganisationalUnit().getName();
            default:
                return null;
        }
    }

    public static String generateGoodsDescription(LetterOfCredit lc, LetterOfCreditGoodsDescription goodsDescription) {
        return generateGoodsDescription(lc.getPurchaseOrders(), goodsDescription);
    }

    public static String generateGoodsDescriptionFromPurchaseOrderItems(Collection<PurchaseOrder> purchaseOrders) {
        String goodsDescription = "";

        for (PurchaseOrder purchaseOrder : purchaseOrders) {

            for (LineItem purchaseOrderItem : purchaseOrder.getActiveLineItems()) {
                String description = purchaseOrderItem.getDescription();

                if (StringUtils.isNotBlank(description)) {
                    if (StringUtils.isNotBlank(goodsDescription)) {
                        goodsDescription += DELIMITER_COMMA + description;
                    } else {
                        goodsDescription += description;
                    }
                }
            }
        }

        return StringUtils.isNotBlank(goodsDescription) ? goodsDescription : null;
    }

    public static String generateProFormaInvoiceNumber(LetterOfCredit letterOfCredit) {
        List<String> proFormaReferences = new ArrayList<String>();
        for (PurchaseOrder purchaseOrder : letterOfCredit.getPurchaseOrders()) {
            proFormaReferences.add(purchaseOrder.getProFormaReference());
        }
        return StringUtils.join(proFormaReferences, DELIMITER_COMMA);
    }

    public static String generateProFormaInvoiceNumber(Collection<PurchaseOrder> purchaseOrders) {
        List<String> proFormaReferences = new ArrayList<String>();
        for (PurchaseOrder purchaseOrder : purchaseOrders) {
            if (purchaseOrder.getProFormaReference() != null) {
                proFormaReferences.add(purchaseOrder.getProFormaReference());
            }
        }
        return StringUtils.join(proFormaReferences, DELIMITER_COMMA);
    }

    public static Date calculateExpiryDate(Date latestShipmentDate, int presentationPeriod) {
        return DateUtils.addDays(latestShipmentDate, presentationPeriod);
    }

    public static int generatePresentationPeriod(LetterOfCredit letterOfCredit, int defaultPresentationPeriod) {
        int presentationPeriod;

        LetterOfCreditTemplate template = letterOfCredit.getLetterOfCreditTemplate();

        if (template != null && template.getPresentationPeriod() != null) {
            presentationPeriod = template.getPresentationPeriod();
        } else if (letterOfCredit.getBeneficiary().getPresentationDays() != null) {
            presentationPeriod = letterOfCredit.getBeneficiary().getPresentationDays();
        } else {
            presentationPeriod = defaultPresentationPeriod;
        }

        return presentationPeriod;
    }

    public String generateGoodsDescriptionWithPurchaseOrderOwningEntity(LetterOfCredit letterOfCredit) {
        PurchaseOrder purchaseOrder = (PurchaseOrder) letterOfCredit.getPurchaseOrders().toArray()[0];

        // JBR
        //if (purchaseOrder != null) {
        //  return purchaseOrder.getOwningEntity().getOrganisation().getName();
        //}
        return null;
    }

    public static int generateValidityPeriod(LetterOfCredit letterOfCredit) {

        PaymentMethod paymentMethod = letterOfCredit.getTenor().getTenor();
        if (letterOfCredit.getExpiryDate() != null && letterOfCredit.getSubmissionDate() != null) {
            long lcSightValidityPeriod = DateUtils.getDaysBetween2(letterOfCredit.getSubmissionDate(), letterOfCredit.getExpiryDate());
            if (paymentMethod.getCode().equals("LC_SIGHT")) {
                return (int) lcSightValidityPeriod;
            } else if (paymentMethod.getCode().equals("LC_USANCE")) {
                PaymentTerm paymentTerm = letterOfCredit.getTenor().getDays();
                long lcUsanceValidityPeriod = DateUtils.getDaysBetween2(letterOfCredit.getSubmissionDate(),
                        DateUtils.addDays(letterOfCredit.getShippingInfo().getLatestShipmentDate(), paymentTerm.getDays()));
                return (int) (lcSightValidityPeriod > lcUsanceValidityPeriod ? lcSightValidityPeriod : lcUsanceValidityPeriod);
            } else {
                return 0;
            }
        } else {
            return 0;
        }
    }

    public static String generateApplicationReference(Collection<PurchaseOrder> purchaseOrders) {
        StringBuilder reference = new StringBuilder();
        for (PurchaseOrder purchaseOrder : purchaseOrders) {
            String shippingReference = purchaseOrder.getShippingInformation().getShippingReference();

            if (StringUtils.isNotBlank(shippingReference)) {
                if (reference.length() == 0) {
                    reference.append(shippingReference);
                } else {
                    reference.append(DELIMITER_COMMA);
                    reference.append(shippingReference);
                }
//                Commented out due to: Jira: TLC-283
//                if (reference.length() >= 16) {
//                    break;
//                }
//                if (reference.length() == 0) {
//                    int endIndex = (shippingReference.length() > 16) ? 16 : (shippingReference.length());
//                    reference.append(shippingReference.substring(0, endIndex));
//                } else {
//                    if (reference.length() + shippingReference.length() + 1 <= 16) {
//                        reference.append(DELIMITER_COMMA);
//                        reference.append(shippingReference);
//                    } else {
//                        reference.append(DELIMITER_COMMA);
//                        reference.append(shippingReference.substring(0, 16 - reference.length()));
//                    }
//                }
            }
        }

        return reference.toString();
    }

    public static String generateApplicationReference(LetterOfCredit letterOfCredit) {
        return generateApplicationReference(letterOfCredit.getPurchaseOrders());
    }

    public static Date calculateLatestShipmentDate(LetterOfCredit letterOfCredit) {
        return calculateLatestShipmentDate(letterOfCredit.getPurchaseOrders());
    }

    public static Date calculateLatestShipmentDate(Collection<PurchaseOrder> purchaseOrders) {
        Date latestShipmentDate = null;

        for (PurchaseOrder purchaseOrder : purchaseOrders) {
            Date purchaseOrderLatestShipmentDate = purchaseOrder.getOrderDates().getLatestShipmentDate();

            if (purchaseOrderLatestShipmentDate != null) {
                if (latestShipmentDate == null || purchaseOrderLatestShipmentDate.after(latestShipmentDate)) {
                    latestShipmentDate = purchaseOrderLatestShipmentDate;
                }
            }
        }

        //getPurchaseOrder().createPurchaseOrderDateProperty(latestShipmentDate, 
        //SynchronisationUtil.LOCAL_PURCHASE_ORDER_LATEST_SHIPMENT_DATE_PROPERTY);
        return latestShipmentDate;
    }

    public static Date calculateEarliestShipmentDate(LetterOfCredit letterOfCredit) {
        return calculateEarliestShipmentDate(letterOfCredit.getPurchaseOrders());
    }

    public static Date calculateEarliestShipmentDate(Collection<PurchaseOrder> purchaseOrders) {
        Date earliestShipmentDate = null;

        for (PurchaseOrder purchaseOrder : purchaseOrders) {
            Date purchaseOrderEarliestShipmentDate = purchaseOrder.getOrderDates().getEarliestShipmentDate();

            if (purchaseOrderEarliestShipmentDate != null) {
                if (earliestShipmentDate == null || purchaseOrderEarliestShipmentDate.before(earliestShipmentDate)) {
                    earliestShipmentDate = purchaseOrderEarliestShipmentDate;
                }
            }
        }

        //getPurchaseOrder().createPurchaseOrderDateProperty(earliestShipmentDate, 
        //SynchronisationUtil.LOCAL_PURCHASE_ORDER_EARLIEST_SHIPMENT_DATE_PROPERTY);
        return earliestShipmentDate;
    }

    public Money calculateTotalInvoice(Collection<PurchaseOrder> purchaseOrders) {
        //Money totalInvoice = null;
        BigDecimal totalInvoice = null;
        Currency totalInvoiceCurrency = null;

        for (PurchaseOrder order : purchaseOrders) {
            if (totalInvoiceCurrency == null) {
                totalInvoiceCurrency = order.getCurrency();
            }
            if (totalInvoice == null) {
                totalInvoice = order.getTotalInvoiceValue();
            } else {
                if (order.getTotalInvoiceValue() != null) {
                    totalInvoice = totalInvoice.add(order.getTotalInvoiceValue());
                }
            }
        }

        //getPurchaseOrder().createPurchaseOrderTotalInvoiceProperty(totalInvoice);
        // JBR
        //return totalInvoice;
        return new Money(MathUtils.setScale(totalInvoice, 2), totalInvoiceCurrency);
    }

    public Money calculateTotalInvoice(LetterOfCredit letterOfCredit) {
        return calculateTotalInvoice(letterOfCredit.getPurchaseOrders());
    }

    public Date getSignedOffByLSPDate(LetterOfCredit letterOfCredit) {
        return getLatestLSPSignOffDateForLCFromPurchaseOrders(letterOfCredit);
    }

    //This method returns the latest LSP signoff date for an LC (Used on the search reports). If there are any orders that haven't been signed off, 
    //then null is returned.
    private Date getLatestLSPSignOffDateForLCFromPurchaseOrders(LetterOfCredit letterOfCredit) {
        Collection<PurchaseOrder> orders = letterOfCredit.getPurchaseOrders();
        Date latestLSPSignOffDate = null;
        for (PurchaseOrder order : orders) {
            //Date lspDate = order.getSignedOffByLSPDate();
            // JBR
            Date lspDate = null;
            if (lspDate != null) {
                if (latestLSPSignOffDate == null || latestLSPSignOffDate.before(lspDate)) {
                    latestLSPSignOffDate = lspDate;
                }
            } else {
                latestLSPSignOffDate = null;
                break;
            }
        }
        return latestLSPSignOffDate;
    }
}