CostsInvoice.java
package com.tradecloud.domain.document.invoice;
import com.tradecloud.common.base.HibernateUtils;
import com.tradecloud.common.base.PersistenceBase;
import com.tradecloud.domain.comment.AddedCommentIncCost;
import com.tradecloud.domain.comment.CommentType;
import com.tradecloud.domain.comment.Commentable;
import com.tradecloud.domain.common.Currency;
import com.tradecloud.domain.common.Incoterm;
import com.tradecloud.domain.configuration.SPICostlineCurrency;
import com.tradecloud.domain.container.Container;
import com.tradecloud.domain.costing.*;
import com.tradecloud.domain.costing.clean.*;
import com.tradecloud.domain.document.Document;
import com.tradecloud.domain.document.PaymentState;
import com.tradecloud.domain.export.ExportCosting;
import com.tradecloud.domain.export.ExportParty;
import com.tradecloud.domain.item.ItemType;
import com.tradecloud.domain.model.ordermanagement.Consignment;
import com.tradecloud.domain.model.ordermanagement.Exposure;
import com.tradecloud.domain.model.ordermanagement.Order;
import com.tradecloud.domain.model.organisationalunit.OrganisationalUnit;
import com.tradecloud.domain.model.payment.ActualPaymentBasis;
import com.tradecloud.domain.model.payment.EstimatedPaymentBasis;
import com.tradecloud.domain.model.shipment.ShipmentState;
import com.tradecloud.domain.model.shipment.ShippingMode;
import com.tradecloud.domain.payment.Payable;
import com.tradecloud.domain.settlement.PlannedSettlementType;
import com.tradecloud.domain.settlement.Settleable;
import com.tradecloud.domain.shipment.AirShipment;
import com.tradecloud.domain.shipment.SeaShipment;
import com.tradecloud.domain.shipment.Shipment;
import com.tradecloud.domain.supplier.OrganisationalUnitSupplier;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang3.NotImplementedException;
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.validation.constraints.Size;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlTransient;
import java.math.BigDecimal;
import java.util.*;
/**
* Generic CostsInvoice entity.
*/
@Entity
@Table(name = "costsinvoice")
@Inheritance(strategy = InheritanceType.JOINED)
@NamedQueries({@NamedQuery(name = "findInvoiceById",
query = "from CostsInvoice ci left join fetch ci.costLineCosting.costLineCostingCells where ci.id=:id")})
public abstract class CostsInvoice extends Document implements Actual, Commentable<AddedCommentIncCost>, Payable, Settleable, Exposure, Costable {
private static final long serialVersionUID = 1L;
/*
* Cache of costables keys and their related CostApplicationBasis values.
*/
@Transient
@XmlTransient
private final Map<String, Map<CostApplicationBasis, BigDecimal>> costableToCostApplicationBasisAmountCache = new HashMap<>();
protected boolean distributableByVolume;
protected boolean distributableByWeight;
/**
* Costs invoices can be associated with Shipments or Consignments or Both!
*/
@ManyToOne(fetch = FetchType.LAZY)
@XmlTransient
protected Shipment shipment;
@ManyToOne(fetch = FetchType.LAZY)
@XmlTransient
protected Consignment consignment;
@NotNull(message = "Currency is required")
@ManyToOne(optional = false)
@XmlElement(name = "Currency")
protected Currency currency;
@NotNull(message = "grossValue is required")
@Basic(optional = false)
@XmlAttribute
protected BigDecimal grossValue;
@Temporal(TemporalType.DATE)
@XmlAttribute
protected Date estimatedSettlementDate;
@NotNull
@Basic(optional = false)
protected BigDecimal costingCurrencyTotalValue = new BigDecimal("0.00");
@XmlElementWrapper(name = "ActualConsignments")
@XmlElement(name = "ActualConsignment")
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@OrderBy(value = "addedToShipmentDate")
@Fetch(value = FetchMode.SELECT)
private Set<ActualConsignment> actualConsignments = new LinkedHashSet<>();
@XmlAttribute
private BigDecimal customsDutyROE = BigDecimal.ZERO;
private transient BigDecimal forwardRate = BigDecimal.ZERO;
private transient BigDecimal spotRate = BigDecimal.ZERO;
@NotNull
@Basic(optional = false)
private BigDecimal totalValue = new BigDecimal("0.00");
private String additionalReference;
/**
* Various cost line costings to allow the costing to be broken down at each level.
*/
@Embedded
@XmlElement(name = "CostLineCosting")
private CostLineCosting costLineCosting = new CostLineCosting();
@XmlAttribute
@Temporal(TemporalType.TIMESTAMP)
private Date addedToConsignmentDate;
@XmlAttribute
@Temporal(TemporalType.TIMESTAMP)
private Date addedToShipmentDate;
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
@XmlElement
@ForeignKey(name = "fk_costedTotals")
private CostedTotals costedTotals = new CostedTotals();
@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "costsinvoice_freetextcomments", joinColumns = {@JoinColumn(name = "costsinvoice_id", unique = false)})
@Column(name = "reason", unique = true)
@ForeignKey(name = "fk_invoice")
@XmlElementWrapper(name = "FreeTextComments")
@XmlElement(name = "FreeTextComment")
@Fetch(value = FetchMode.SUBSELECT)
protected List<AddedCommentIncCost> comments = new ArrayList<AddedCommentIncCost>();
@Transient
@XmlTransient
private ShipmentState toShipmentState;
@Size(max = 255, message = "invoice number exceeded 255 character")
private String number;
@XmlTransient
@ElementCollection
private Map<String, BigDecimal> costlineBondedAmount = new HashMap<String, BigDecimal>();
private transient ExchangeRateCache exchangeRateCache = new ExchangeRateCache();
private boolean existsInDMS;
public CostsInvoice() {
super();
}
@Override
public Shipment getShipment() {
return shipment;
}
@Override
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
@Override
public BigDecimal getGrossValue() {
return grossValue;
}
public void setGrossValue(BigDecimal grossValue) {
this.grossValue = grossValue;
}
public Date getEstimatedSettlementDate() {
return estimatedSettlementDate;
}
public void setEstimatedSettlementDate(Date estimatedSettlementDate) {
this.estimatedSettlementDate = estimatedSettlementDate;
}
@Override
public ItemType getItemType() {
return null;
}
public Date getSpotDate() {
Shipment shipment1 = HibernateUtils.getNonProxyObject(getShipment());
if (shipment1 != null) {
if (shipment1.getShippingMode() == ShippingMode.SEA
&& ((SeaShipment) shipment1).getMasterBillOfLadingDate() != null)
return ((SeaShipment) shipment1).getMasterBillOfLadingDate();
if (shipment1.getShippingMode() == ShippingMode.AIR
&& ((AirShipment) shipment1).getMasterAirwayBillIssueDate() != null)
return ((AirShipment) shipment1).getMasterAirwayBillIssueDate();
return shipment1.getBillOfLadingDate();
}
return null;
}
public void setSpotDate(Date spotDate) {
//not editable
}
public Consignment getConsignment() {
return consignment;
}
public List<ActualConsignment> getActualConsignmentList() {
return new ArrayList<>(actualConsignments);
}
public Set<ActualConsignment> getActualConsignments() {
return actualConsignments;
}
public void setActualConsignments(Set<ActualConsignment> actualConsignments) {
this.actualConsignments = actualConsignments;
}
public void addActualConsignment(ActualConsignment actualConsignment) {
actualConsignments.add(actualConsignment);
actualConsignment.setCostsInvoice(this);
}
public BigDecimal getCustomsDutyROE() {
return customsDutyROE;
}
public void setCustomsDutyROE(BigDecimal customsDutyROE) {
this.customsDutyROE = customsDutyROE;
}
public BigDecimal getForwardRate() {
return forwardRate;
}
public void setForwardRate(BigDecimal forwardRate) {
this.forwardRate = forwardRate;
}
public BigDecimal getSpotRate() {
return spotRate;
}
public void setSpotRate(BigDecimal spotRate) {
this.spotRate = spotRate;
}
@Override
public String toString() {
return new ToStringBuilder(this).append(currency).append(grossValue).append(super.toString()).toString();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
// Do not use class.equals. This can return false for proxy objects
if (!HibernateUtils.proxyClassEquals(this, obj)) {
return false;
}
CostsInvoice other = (CostsInvoice) obj;
return new EqualsBuilder()
.appendSuper(super.equals(obj))
.append(currency, other.getCurrency())
.append(grossValue, other.getGrossValue())
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.appendSuper(super.hashCode())
.append(currency)
.append(grossValue).toHashCode();
}
public ActualConsignment getConsignmentWithNumber(String number) {
for (ActualConsignment actualConsignment : getActualConsignments()) {
if (actualConsignment.getNumber().equals(number)) {
return actualConsignment;
}
}
return null;
}
@Override
public BigDecimal getInvoiceQuantity() {
// Empty implementation so concrete subclasses can ignore if they don't need this functionality
return null;
}
@Override
public void setInvoiceQuantity(BigDecimal invoiceQuantity) {
// Empty implementation so concrete subclasses can ignore if they don't need this functionality
}
@Override
public BigDecimal getOrderQuantity() {
// Empty implementation so concrete subclasses can ignore if they don't need this functionality
return null;
}
@Override
public void setOrderQuantity(BigDecimal orderQuantity) {
// Empty implementation so concrete subclasses can ignore if they don't need this functionality
}
@Override
public Map<TotalsDistributionType, BigDecimal> getTotalsDistribution() {
// Empty implementation so concrete subclasses can ignore if they don't need this functionality
return null;
}
@Override
public BigDecimal getTotalInvoiceValue() {
return totalValue;
}
@Override
public void setTotalInvoiceValue(BigDecimal totalValue) {
this.totalValue = totalValue;
}
@Transient
@Override
public BigDecimal getTotalSettleableValue() {
return grossValue;
}
public BigDecimal getCostingCurrencyTotalValue() {
return costingCurrencyTotalValue;
}
public void setCostingCurrencyTotalValue(BigDecimal costingCurrencyTotalValue) {
this.costingCurrencyTotalValue = costingCurrencyTotalValue;
}
/**
* Return the weighted average forward rate from the invoice transaction currency to the costing currency.
*
* @return the weighted average forward rate
*/
public abstract BigDecimal getWeightedAverageForwardRateOfExchange();
public abstract BigDecimal getWeightedAverageSpotRateOfExchange();
@Override
public CostLineCosting getCostLineCosting() {
return costLineCosting;
}
public void setCostLineCosting(CostLineCosting costLineCosting) {
this.costLineCosting = costLineCosting;
}
public BigDecimal lookupTransactionAmount(String costLineCode, Order order) {
CostLineCostingCell costLineCostingCell = getCostLineCostingCell(costLineCode, order);
return costLineCostingCell != null ? costLineCostingCell.getTransactionAmount() : BigDecimal.ZERO;
}
public CostLineCostingCell getCostLineCostingCell(String costLineCode, Order order) {
final List<ActualConsignment> actualConsignmentList = getActualConsignmentList();
for (ActualConsignment actualConsignment : actualConsignmentList) {
final List<ActualOrder> actualOrderList = actualConsignment.getActualOrderList();
for (ActualOrder actualOrder : actualOrderList) {
if (actualOrder.getReference().equals(order.getOrderReference()) && actualOrder.getNumber().equals(order.getNumber())) {
log.debug("Found matching actual order.");
return (CostLineCostingCell) actualOrder.getCostLineCosting().getCostingCell(costLineCode);
}
}
}
return null;
}
@Override
public CostableType getCostableType() {
return CostableType.INVOICE;
}
@Override
public Costed getParent() {
return null;
}
@Override
public String getKey() {
return new StringBuilder(getClass().getCanonicalName()).append("-").append(hashCode()).toString();
}
@Override
public CostsInvoice getCostsInvoice() {
return this;
}
public Map<String, Map<CostApplicationBasis, BigDecimal>> getCostableToCostApplicationBasisAmountCache() {
return costableToCostApplicationBasisAmountCache;
}
public void clearCostApplicationBasisAmounts() {
costableToCostApplicationBasisAmountCache.clear();
}
public List<ActualLineItem> getActualLineItems() {
List<ActualLineItem> actualLineItems = new ArrayList<>();
for (ActualConsignment actualConsignment : actualConsignments) {
actualLineItems.addAll(actualConsignment.getActualItems());
}
return actualLineItems;
}
public List<ActualOrder> getActualOrders() {
List<ActualOrder> actualOrders = new ArrayList<>();
for (ActualConsignment actualConsignment : actualConsignments) {
actualOrders.addAll(actualConsignment.getActualOrderList());
}
return actualOrders;
}
public Date getAddedToConsignmentDate() {
return addedToConsignmentDate;
}
public void setAddedToConsignmentDate(Date addedToConsignmentDate) {
this.addedToConsignmentDate = addedToConsignmentDate;
}
public Date getAddedToShipmentDate() {
return addedToShipmentDate;
}
public void setAddedToShipmentDate(Date addedToShipmentDate) {
this.addedToShipmentDate = addedToShipmentDate;
}
/**
* This field will be set to true if 1 of the line items linked to the structure has a volume value.
*
* @return
*/
@Override
public boolean isDistributableByVolume() {
return distributableByVolume;
}
public void setDistributableByVolume(boolean distributableByVolume) {
this.distributableByVolume = distributableByVolume;
}
/**
* This field will be set to true if 1 of the line items linked to the structure has a weight value.
*
* @return
*/
@Override
public boolean isDistributableByWeight() {
return distributableByWeight;
}
public void setDistributableByWeight(boolean distributableByWeight) {
this.distributableByWeight = distributableByWeight;
}
@Override
public CostedTotals getCostedTotals() {
if (costedTotals == null) {
costedTotals = new CostedTotals();
}
return costedTotals;
}
@Override
public void setCostedTotals(CostedTotals costedTotals) {
this.costedTotals = costedTotals;
}
@Override
public Costed findRootParent() {
return this;
}
@Override
public boolean isItem() {
return false;
}
@Override
public boolean isOrder() {
return false;
}
@Override
public boolean isConsignment() {
return false;
}
public void setConsignment(Consignment consignment) {
this.consignment = consignment;
}
@Override
public boolean isShipment() {
return false;
}
public void setShipment(Shipment shipment) {
this.shipment = shipment;
}
@Override
public boolean isCostsInvoice() {
return true;
}
@Override
public boolean isActual() {
return true;
}
@Override
public boolean match(Actual actual) {
return false;
}
@Override
public String getReferenceWithShippingRef() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
@Override
public PaymentState getPaymentState() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
@Override
public PlannedSettlementType getPlannedSettlementType() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
@Override
public ActualPaymentBasis getActualPaymentBasis() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
@Override
public EstimatedPaymentBasis getEstimatedPaymentBasis() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
@Override
public EstimatedPaymentBasis getEstimatedPaymentBasis2() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
@Override
public PlannedSettlementHelper getPlannedSettlementHelper() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
@Override
public OrganisationalUnitSupplier getSupplier() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
public ExportParty getExportParty() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
@Override
public void clearPlannedSettlements() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
public boolean isSupplierInvoice() {
return false;
}
@Override
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public BigDecimal getSellPriceInclusiveAmount() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
@Override
public void setSellPriceInclusiveAmount(BigDecimal sellPriceInclusiveAmount) {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
@Override
public BigDecimal getSellPriceExclusiveAmount() {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
@Override
public void setSellPriceExclusiveAmount(BigDecimal sellPriceExclusiveAmount) {
throw new UnsupportedOperationException(" not supported by " + this.getClass());
}
public ShipmentState getToShipmentState() {
return toShipmentState;
}
public void setToShipmentState(ShipmentState toShipmentState) {
this.toShipmentState = toShipmentState;
}
@Override
public OrganisationalUnit getOrderOrganisationalUnit() {
Order order = shipment.getOrders().stream().findFirst().orElse(null);
return order != null ? order.getOrderOrganisationalUnit() : null;
}
public SPICostlineCurrency getSpiCostlineCurrency() {
return null;
}
@Override
public Map getCostlineBondedAmount() {
return costlineBondedAmount;
}
public void setCostlineBondedAmount(Map<String, BigDecimal> costlineBondedAmount) {
this.costlineBondedAmount = costlineBondedAmount;
}
@Override
public List<AddedCommentIncCost> getComments() {
return comments;
}
@Override
public void setComments(List<AddedCommentIncCost> comments) {
this.comments = (List<AddedCommentIncCost>) comments;
}
@Override
public CommentType getCommentType() {
return CommentType.INVOICE;
}
public abstract String getType();
@Override
public Incoterm getIncoterm() {
return shipment.getIncoterm();
}
@Override
public CostingContextType getCostingContextType() {
return CostingContextType.IMPORT;
}
@Override
public Set<? extends Container> getContainers() {
return shipment.getContainers();
}
@Override
public ShippingMode getShippingMode() {
return shipment.getShippingMode();
}
@Override
public ShippingMode getMultiModalShippingMode() {
return getShipment().getMultiModalShippingMode();
}
@Override
public OrganisationalUnit getOrganisationalUnit() {
return null;
}
@Override
public List<? extends PersistenceBase> getLineItems() {
return shipment.getLineItems();
}
@Override
public Date getArrivalDateAtPlaceOfDischarge() {
return shipment.getArrivalDateAtPlaceOfDischarge();
}
@Override
public CostableCostDefinition getCostableCostDefinition() {
return shipment.getCostableCostDefinition();
}
@Override
public void setCostableCostDefinition(CostableCostDefinition costableCostDefinition) {
this.shipment.setCostableCostDefinition(costableCostDefinition);
}
public BigDecimal getTotalValue() {
return totalValue;
}
public void setTotalValue(BigDecimal totalValue) {
this.totalValue = totalValue;
}
public void setExchangeRateCache(ExchangeRateCache exchangeRateCache) {
this.exchangeRateCache = exchangeRateCache;
}
public ExchangeRateCache getExchangeRateCache() {
return exchangeRateCache;
}
public boolean isExistsInDMS() {
return existsInDMS;
}
public void setExistsInDMS(boolean existsInDMS) {
this.existsInDMS = existsInDMS;
}
public ExportCosting getExportCosting() {
throw new NotImplementedException("please implement");
}
public String getAdditionalReference() {
return additionalReference;
}
public void setAdditionalReference(String additionalReference) {
this.additionalReference = additionalReference;
}
}