PlannedSettlement.java
package com.tradecloud.domain.settlement;
import com.tradecloud.domain.base.utils.DateUtils;
import com.tradecloud.domain.base.utils.MathUtils;
import com.tradecloud.domain.common.Currency;
import com.tradecloud.domain.document.PaymentState;
import com.tradecloud.domain.document.invoice.CostsInvoice;
import com.tradecloud.domain.document.invoice.PlannedSettlementHelper;
import com.tradecloud.domain.exception.InvalidEntityException;
import com.tradecloud.domain.model.ordermanagement.Order;
import com.tradecloud.domain.model.payment.ActualPaymentBasis;
import com.tradecloud.domain.model.payment.EstimatedPaymentBasis;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.ForeignKey;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;
@Entity
@Table(name = "plannedsettlement")
public class PlannedSettlement extends PlannedSettlementDetail implements Cloneable {
private static final long serialVersionUID = 1L;
private static final SimpleDateFormat dateFormat = new SimpleDateFormat();
static {
dateFormat.applyPattern("dd-MM-yyyy");
}
@Enumerated(EnumType.STRING)
@XmlAttribute
private PlannedSettlementType type;
@XmlAttribute
private boolean active;
@XmlAttribute
private boolean formerlyExposed;
@ManyToOne
@XmlElement(name = "EstimatedPaymentBasis")
private EstimatedPaymentBasis estimatedPaymentBasis;
@ManyToOne
@XmlElement(name = "ActualPaymentBasis")
private ActualPaymentBasis actualPaymentBasis;
@XmlAttribute
private BigDecimal amountInCostingCurrency;
/**
* Probably a bad name for it now as i'm not really using that pattern.
* Really what this object represents is the system default planned settlement
*/
@OneToOne(cascade = CascadeType.ALL)
@Deprecated
//we don't use of this object , we should remove it.
private PlannedSettlement plannedSettlementMemento;
/**
* Persist the default value so we can tell if it's been edited since creation.
*/
private String defaultValue;
@Enumerated(EnumType.STRING)
@XmlAttribute
private SettlementTreasuryState treasuryState;
@XmlElementWrapper(name = "Payments")
@XmlElement(name = "Payment")
@OneToMany(cascade = CascadeType.ALL, mappedBy = "plannedSettlement")
@Fetch(value = FetchMode.SUBSELECT)
private Set<Payment> payments = new LinkedHashSet<Payment>();
@XmlElementWrapper(name = "PlannedSettlementOrders")
@XmlElement(name = "PlannedSettlementOrder")
@ForeignKey(name = "fk_plannedSettlementorder")
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.DETACH, CascadeType.REFRESH}, mappedBy = "plannedSettlement",
orphanRemoval = true, fetch = FetchType.LAZY)
@OrderBy(value = "addedToConsignmentDate")
private Set<PlannedSettlementOrder> plannedSettlementOrders = new LinkedHashSet<PlannedSettlementOrder>();
@NotNull
@XmlAttribute
protected Integer days;
/**
* Persist the state of the plannedSettlement.
* DEFAULT unsettled
*/
@Enumerated(EnumType.STRING)
@XmlAttribute
private PaymentState paymentState;
private String label;
@ManyToOne(fetch = FetchType.LAZY)
private Order order;
@ManyToOne(fetch = FetchType.LAZY)
private CostsInvoice invoice;
public static PlannedSettlementBuilder createBuilder() {
return new PlannedSettlementBuilder();
}
/**
* Constructor required by the framework. The PlannedSettlementBuilder should be used instead.
*/
public PlannedSettlement() {
}
public PlannedSettlement(PlannedSettlementDetail detail, Integer days, PlannedSettlementType type, boolean active, boolean formerlyExposed,
EstimatedPaymentBasis estimatedPaymentBasis, ActualPaymentBasis actualPaymentBasis, BigDecimal amountInCostingCurrency,
SettlementTreasuryState treasuryState, PaymentState paymentState) {
super(detail);
this.type = type;
this.active = active;
this.formerlyExposed = formerlyExposed;
this.days = days;
this.estimatedPaymentBasis = estimatedPaymentBasis;
this.actualPaymentBasis = actualPaymentBasis;
this.amountInCostingCurrency = amountInCostingCurrency;
this.treasuryState = treasuryState;
this.paymentState = paymentState;
}
/**
* We need to know if the Planned Settlement has been edited from it's default version.
*
* Different rules apply if it has been edited by a user.
*
* Set the default value in the builder at creation time. If it's different then it's been changed. Simple as.
*
* @return true if it still has all the default values and hasn't been edited.
*/
public boolean isDefault() {
//return this.equals(getPlannedSettlementMemento());
return !(overriddenAmount || overriddenForwardRate || overriddenSettlementDate || overriddenSpotRate || overriddenPercentage);
}
@Override
public String toString() {
return new ToStringBuilder(this).append(type).append(active).append(formerlyExposed).append(amount).append(estimatedPaymentBasis)
.append(actualPaymentBasis).append(settlementDate).append(forwardRate).append(spotRate).append(amountInCostingCurrency)
.append(treasuryState).append(defaultValue).toString();
}
public PaymentState getPaymentState() {
return paymentState;
}
public void setPaymentState(PaymentState paymentState) {
this.paymentState = paymentState;
}
public PlannedSettlementType getType() {
return type;
}
public void setType(PlannedSettlementType type) {
this.type = type;
}
public EstimatedPaymentBasis getEstimatedPaymentBasis() {
return estimatedPaymentBasis;
}
public void setEstimatedPaymentBasis(EstimatedPaymentBasis estimatedPaymentBasis) {
this.estimatedPaymentBasis = estimatedPaymentBasis;
}
public ActualPaymentBasis getActualPaymentBasis() {
return actualPaymentBasis;
}
public void setActualPaymentBasis(ActualPaymentBasis actualPaymentBasis) {
this.actualPaymentBasis = actualPaymentBasis;
}
public String getFormattedSettlementDate() {
return dateFormat.format(settlementDate);
}
public String getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
public Set<Payment> getPayments() {
return payments;
}
public void setPayments(Set<Payment> payments) {
this.payments = payments;
}
public Set<PlannedSettlementOrder> getPlannedSettlementOrders() {
return plannedSettlementOrders;
}
public void setPlannedSettlementOrders(Set<PlannedSettlementOrder> plannedSettlementOrders) {
this.plannedSettlementOrders = plannedSettlementOrders;
}
/**
* Checks the value of the settlement date against what the system thinks the default value should be.
* The default value is held in the memento
*
* @return
*/
public boolean isSettlementDateOutOfSynch() {
return getPlannedSettlementMemento() != null && getPlannedSettlementMemento().getSettlementDate().compareTo(getSettlementDate()) != 0;
}
public BigDecimal getAmountInCostingCurrencyUsingSpotRate() {
BigDecimal amountInCostingCurrencyUsingSpotRate = BigDecimal.ONE;
if (amount == null || spotRate == null) {
return BigDecimal.ZERO;
}
if (plannedSettlementOrders == null || plannedSettlementOrders.isEmpty()) {
// return this.getAmount().multiply(getSpotRate());
return MathUtils.multiply(this.getAmount(), getSpotRate());
}
PlannedSettlementHelper plannedSettlementHelper = new PlannedSettlementHelper(Collections.singleton(this));
return plannedSettlementHelper.getOrderCostingCurrencyTotalValueUsingSpotRate();
}
public BigDecimal getParentAmountInCostingSpotRate() {
BigDecimal amountInCostingCurrencyUsingSpotRate = BigDecimal.ONE;
if (spotRate != null) {
amountInCostingCurrencyUsingSpotRate = MathUtils.multiply(this.getAmount(), getSpotRate());
}
return amountInCostingCurrencyUsingSpotRate;
}
public void setAmountInCostingCurrency(BigDecimal amountInCostingCurrency) {
this.amountInCostingCurrency = amountInCostingCurrency;
}
public SettlementTreasuryState getTreasuryState() {
return treasuryState;
}
public void setTreasuryState(SettlementTreasuryState treasuryState) {
this.treasuryState = treasuryState;
}
@Override
public Boolean getActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public void setFormerlyExposed(boolean formerlyExposed) {
this.formerlyExposed = formerlyExposed;
}
/**
* Does this settlement have any treasury implications.
*
* @return
*/
public boolean hasTreasuryImplication() {
return isFormerlyExposed(); // getTreasuryState().equals(SettlementTreasuryState.NEW);
}
/**
* has this settlement ever been exposed to treasury?
*
* @return
*/
public boolean isFormerlyExposed() {
return formerlyExposed;
}
@Override
public Integer getDays() {
return days;
}
public void setDays(Integer days) {
this.days = days;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(getForwardRate()).append(getSpotRate()).append(getSettlementDate()).append(days).
append(getSplitPaymentType()).toHashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof PlannedSettlement)) {
return false;
}
PlannedSettlement other = (PlannedSettlement) obj;
// need to put some tolerance when dealing with numbers.
// without tolerance BigDecimal of 2.00 is not equals to 2.00000
return MathUtils.areNumbersCloselyEqual(amount, other.getAmount(), 4)
&& MathUtils.areNumbersCloselyEqual(forwardRate, other.getForwardRate(), 4)
&& MathUtils.areNumbersCloselyEqual(spotRate, other.getSpotRate(), 4)
&& new EqualsBuilder().append(DateUtils.toT_YMDFormat(settlementDate), DateUtils.toT_YMDFormat(other.getSettlementDate()))
.append(days, other.days).append(getSplitPaymentType(), other.getSplitPaymentType()).isEquals();
}
@Deprecated
//we don't use of this object , we should it.
public PlannedSettlement getPlannedSettlementMemento() {
return plannedSettlementMemento;
}
public void setPlannedSettlementMemento(PlannedSettlement plannedSettlementMemento) {
this.plannedSettlementMemento = plannedSettlementMemento;
}
@Override
public PlannedSettlement clone() {
PlannedSettlement clone = (PlannedSettlement) super.clone();
return clone;
}
@Override
@Transient
public BigDecimal getAmountInCostingCurrency() {
if (amount == null || forwardRate == null) {
return BigDecimal.ZERO;
}
if (plannedSettlementOrders == null || plannedSettlementOrders.isEmpty()) {
return MathUtils.multiply(amount, getForwardRate());
} else {
PlannedSettlementHelper plannedSettlementHelper = new PlannedSettlementHelper(Collections.singleton(this));
return plannedSettlementHelper.getOrderCostingCurrencyTotalValue();
}
}
public void calculateCostingAmount() {
this.amountInCostingCurrency = MathUtils.multiply(forwardRate, amount);
}
public BigDecimal getParentAmountInCostingCurrency() {
if (amount == null || forwardRate == null) {
return BigDecimal.ZERO;
}
return MathUtils.multiply(amount, getForwardRate());
}
public void addPlannedSettlementOrder(PlannedSettlementOrder plannedSettlementOrder) {
this.plannedSettlementOrders.add(plannedSettlementOrder);
}
public static final class PlannedSettlementBuilder {
private PlannedSettlementType type;
private boolean active;
private boolean formerlyExposed;
private BigDecimal amount;
private EstimatedPaymentBasis estimatedPaymentBasis;
private ActualPaymentBasis actualPaymentBasis;
private Date settlementDate;
private BigDecimal forwardRate;
private BigDecimal spotRate;
private BigDecimal amountInCostingCurrency;
private SettlementTreasuryState treasuryState;
private Currency currency;
private Integer days;
private PaymentState paymentState;
private String number;
private Order order;
private CostsInvoice invoice;
/**
* Private constructor to prevent instantiation.
*/
private PlannedSettlementBuilder() {
}
public PlannedSettlement build() {
// Calculate this value
validate();
calculateCostingAmount();
PlannedSettlementDetail detail = new PlannedSettlementDetail();
detail.setAmount(amount);
detail.setSettlementDate(settlementDate);
detail.setForwardRate(forwardRate);
detail.setSpotRate(spotRate);
detail.setCurrency(currency);
detail.setNumber(number);
PlannedSettlement ps =
new PlannedSettlement(detail, days, type, active, formerlyExposed, estimatedPaymentBasis, actualPaymentBasis,
amountInCostingCurrency, treasuryState, paymentState);
ps.setPlannedSettlementMemento(ps.clone());
ps.setOrder(order);
ps.setInvoice(invoice);
return ps;
}
private void calculateCostingAmount() {
this.amountInCostingCurrency = MathUtils.multiplyVA(forwardRate, amount);
}
private void validate() {
if (amount == null) {
throw new InvalidEntityException("Amount cannot be null");
}
if (forwardRate == null) {
throw new InvalidEntityException("Forward Rate cannot be null");
}
if (settlementDate == null) {
throw new InvalidEntityException("Settlement Date cannot be null");
}
if (days == null) {
throw new InvalidEntityException("Days cannot be null");
}
}
public PlannedSettlementBuilder setPlannedSettlementType(PlannedSettlementType type) {
this.type = type;
return this;
}
public PlannedSettlementBuilder setActive(boolean active) {
this.active = active;
return this;
}
public PlannedSettlementBuilder setFormerlyExposed(boolean formerlyExposed) {
this.formerlyExposed = formerlyExposed;
return this;
}
public PlannedSettlementBuilder setAmount(BigDecimal amount) {
this.amount = amount;
return this;
}
public PlannedSettlementBuilder setEstimatedPaymentBasis(EstimatedPaymentBasis estimatedPaymentBasis) {
this.estimatedPaymentBasis = estimatedPaymentBasis;
return this;
}
public PlannedSettlementBuilder setActualPaymentBasis(ActualPaymentBasis actualPaymentBasis) {
this.actualPaymentBasis = actualPaymentBasis;
return this;
}
public PlannedSettlementBuilder setSettlementDate(Date settlementDate) {
this.settlementDate = settlementDate;
return this;
}
public PlannedSettlementBuilder setForwardRate(BigDecimal forwardRate) {
this.forwardRate = forwardRate;
return this;
}
public PlannedSettlementBuilder setSpotRate(BigDecimal spotRate) {
this.spotRate = spotRate;
return this;
}
public PlannedSettlementBuilder setAmountInCostingCurrency(BigDecimal amountInCostingCurrency) {
this.amountInCostingCurrency = amountInCostingCurrency;
return this;
}
public PlannedSettlementBuilder setTreasuryState(SettlementTreasuryState treasuryState) {
this.treasuryState = treasuryState;
return this;
}
public PlannedSettlementBuilder setCurrency(Currency currency) {
this.currency = currency;
return this;
}
public PlannedSettlementBuilder setDays(Integer days) {
this.days = days;
return this;
}
public PlannedSettlementBuilder setInvoice(CostsInvoice invoice) {
this.invoice = invoice;
return this;
}
public PlannedSettlementBuilder setOrder(Order order) {
this.order = order;
return this;
}
public PaymentState getPaymentState() {
return paymentState;
}
public void setPaymentState(PaymentState paymentState) {
this.paymentState = paymentState;
}
public PlannedSettlementBuilder setNumber(String number) {
this.number = number;
return this;
}
}
public CostsInvoice getInvoice() {
return invoice;
}
public void setInvoice(CostsInvoice invoice) {
this.invoice = invoice;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}